Merge commit '685a8c81f5387eb165566f7ec48a79241b3d35d0' into dev-release
diff --git a/.gitignore b/.gitignore
index 80c9662..07f90a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -262,6 +262,8 @@
tools/*/art-9.0.0.tar.gz
tools/*/art-10.0.0
tools/*/art-10.0.0.tar.gz
+tools/*/host/art-12.0.0-beta4
+tools/*/host/art-12.0.0-beta4.tar.gz
tools/*/art.tar.gz
tools/*/dalvik
tools/*/dalvik-4.0.4
diff --git a/build.gradle b/build.gradle
index 4a8dd81..8b0525f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -361,6 +361,7 @@
"linux/art-8.1.0",
"linux/art-9.0.0",
"linux/art-10.0.0",
+ "linux/host/art-12.0.0-beta4",
"linux/dalvik",
"linux/dalvik-4.0.4",
"${osString}/dx",
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 9fe678c..85170a7 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -390,6 +390,24 @@
}
}
builders {
+ name: "linux-android-12.0.0"
+ mixins: "linux"
+ mixins: "normal"
+ recipe {
+ properties: "tool:r8"
+ properties: "dex_vm:12.0.0"
+ }
+ }
+ builders {
+ name: "linux-android-12.0.0_release"
+ mixins: "linux"
+ mixins: "normal"
+ recipe {
+ properties: "tool:r8"
+ properties: "dex_vm:12.0.0"
+ }
+ }
+ builders {
name: "linux-internal"
mixins: "linux"
mixins: "internal"
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index b881778..c105138 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -347,6 +347,50 @@
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
}
builders {
+ name: "linux-android=12.0.0"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ recipe {
+ name: "rex"
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+ }
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ }
+ builders {
+ name: "linux-android=12.0.0_release"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ recipe {
+ name: "rex"
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+ }
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ }
+ builders {
name: "linux-android=8.1.0"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index 58474a2..7ffcae6 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -186,6 +186,16 @@
short_name: "android=10.0.0_release"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-android=12.0.0"
+ category: "R8"
+ short_name: "android=12.0.0"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android=12.0.0_release"
+ category: "R8 release"
+ short_name: "android=12.0.0_release"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/windows"
category: "R8"
short_name: "windows"
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
index c441677..25f83b5 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -180,6 +180,30 @@
}
builders {
bucket: "ci"
+ name: "linux-android=12.0.0"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
+ name: "linux-android=12.0.0_release"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
name: "linux-android=8.1.0"
repository: "https://r8.googlesource.com/r8"
}
diff --git a/infra/config/global/generated/luci-scheduler.cfg b/infra/config/global/generated/luci-scheduler.cfg
index b4ee1f0..e915f53 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -155,6 +155,24 @@
}
}
job {
+ id: "linux-android=12.0.0"
+ acl_sets: "ci"
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android=12.0.0"
+ }
+}
+job {
+ id: "linux-android=12.0.0_release"
+ acl_sets: "ci"
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android=12.0.0_release"
+ }
+}
+job {
id: "linux-android=8.1.0"
acl_sets: "ci"
buildbucket {
@@ -372,6 +390,7 @@
triggers: "linux-android-6.0.1_release"
triggers: "linux-android-7.0.0_release"
triggers: "linux-android=10.0.0_release"
+ triggers: "linux-android=12.0.0_release"
triggers: "linux-android=8.1.0_release"
triggers: "linux-android=9.0.0_release"
triggers: "linux-d8_jctf_release"
@@ -399,6 +418,7 @@
triggers: "linux-android-6.0.1"
triggers: "linux-android-7.0.0"
triggers: "linux-android=10.0.0"
+ triggers: "linux-android=12.0.0"
triggers: "linux-android=8.1.0"
triggers: "linux-android=9.0.0"
triggers: "linux-d8_jctf"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 8218353..3c2ad37 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -76,6 +76,11 @@
short_name: "10.0.0"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-android-12.0.0"
+ category: "R8"
+ short_name: "12.0.0"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/linux-internal"
category: "R8"
short_name: "internal"
@@ -186,6 +191,11 @@
short_name: "10.0.0"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-android-12.0.0_release"
+ category: "R8 release"
+ short_name: "12.0.0"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/linux-internal_release"
category: "R8 release"
short_name: "internal"
diff --git a/infra/config/global/luci-notify.cfg b/infra/config/global/luci-notify.cfg
index 92b76f3..1e0eb27 100644
--- a/infra/config/global/luci-notify.cfg
+++ b/infra/config/global/luci-notify.cfg
@@ -124,6 +124,16 @@
repository: "https://r8.googlesource.com/r8"
}
builders {
+ name: "linux-android-12.0.0"
+ bucket: "ci"
+ repository: "https://r8.googlesource.com/r8"
+ }
+ builders {
+ name: "linux-android-12.0.0_release"
+ bucket: "ci"
+ repository: "https://r8.googlesource.com/r8"
+ }
+ builders {
name: "linux-internal"
bucket: "ci"
repository: "https://r8.googlesource.com/r8"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 4bd0b89..f585e8d 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -39,6 +39,7 @@
triggers: "linux-android-8.1.0"
triggers: "linux-android-9.0.0"
triggers: "linux-android-10.0.0"
+ triggers: "linux-android-12.0.0"
triggers: "linux-run-on-app-dump"
triggers: "linux-internal"
triggers: "linux-jctf"
@@ -91,6 +92,7 @@
triggers: "linux-android-8.1.0_release"
triggers: "linux-android-9.0.0_release"
triggers: "linux-android-10.0.0_release"
+ triggers: "linux-android-12.0.0_release"
triggers: "linux-internal_release"
triggers: "linux-jctf_release"
triggers: "r8cf-linux-jctf_release"
@@ -529,6 +531,34 @@
}
job {
+ id: "linux-android-12.0.0"
+ acl_sets: "default"
+ triggering_policy: {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 6
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android-12.0.0"
+ }
+}
+
+job {
+ id: "linux-android-12.0.0_release"
+ acl_sets: "default"
+ triggering_policy: {
+ max_batch_size: 1
+ max_concurrent_invocations: 3
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android-12.0.0_release"
+ }
+}
+
+job {
id: "linux-internal"
acl_sets: "default"
buildbucket {
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index e78b09a..beda63e 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -237,6 +237,8 @@
["--dex_vm=9.0.0", "--all_tests"])
r8_tester_with_default("linux-android=10.0.0",
["--dex_vm=10.0.0", "--all_tests"])
+r8_tester_with_default("linux-android=12.0.0",
+ ["--dex_vm=12.0.0", "--all_tests"])
r8_tester_with_default("windows", ["--all_tests"],
dimensions=get_dimensions(windows=True))
diff --git a/scripts/update-host-art.sh b/scripts/update-host-art.sh
index 76572e0..58165cd 100755
--- a/scripts/update-host-art.sh
+++ b/scripts/update-host-art.sh
@@ -109,11 +109,15 @@
# dalvikvm32 or dalvikvm64).
cp $ANDROID_HOST_BUILD/bin/dalvikvm $DEST/bin
cp $ANDROID_HOST_BUILD/bin/dex2oat $DEST/bin
+if [ -e $ANDROID_HOST_BUILD/bin/dex2oat64 ]
+ then cp $ANDROID_HOST_BUILD/bin/dex2oat64 $DEST/bin
+fi
if [ -e $ANDROID_HOST_BUILD/bin/patchoat ]
# File patchoat does not exist on Q anymore.
then cp $ANDROID_HOST_BUILD/bin/patchoat $DEST/bin
fi
+
# Required framework files.
mkdir -p $DEST/framework
cp -R $ANDROID_HOST_BUILD/framework/* $DEST/framework
@@ -127,15 +131,32 @@
# Image files required for dex2oat of actual android apps. We need an actual android product
# image containing framework classes to verify the code against.
mkdir -p $DEST/product/$ANDROID_PRODUCT/system/framework
-cp -r $ANDROID_TARGET_BUILD/product/$ANDROID_PRODUCT/system/framework/* $DEST/product/$ANDROID_PRODUCT/system/framework
+cp -rL $ANDROID_TARGET_BUILD/product/$ANDROID_PRODUCT/system/framework/* $DEST/product/$ANDROID_PRODUCT/system/framework
# Required auxillary files.
-if [ -e $ANDROID_HOST_BUILD/usr/icu ]; then
- mkdir -p $DEST/usr/icu
- cp -r $ANDROID_HOST_BUILD/usr/icu/* $DEST/usr/icu
+if [ -e $ANDROID_HOST_BUILD/apex ]; then
+ mkdir -p $DEST/apex
+ cp -rL $ANDROID_HOST_BUILD/apex/* $DEST/apex
+ if [ -e $ANDROID_HOST_BUILD/com.android.i18n ]; then
+ mkdir -p $DEST/com.android.i18n
+ cp -r $ANDROID_HOST_BUILD/com.android.i18n/* $DEST/com.android.i18n
+ fi
+ if [ -e $ANDROID_HOST_BUILD/com.android.tzdata ]; then
+ mkdir -p $DEST/com.android.tzdata
+ cp -r $ANDROID_HOST_BUILD/com.android.tzdata/* $DEST/com.android.tzdata
+ fi
+ if [ -e $ANDROID_HOST_BUILD/usr ]; then
+ mkdir -p $DEST/usr
+ cp -r $ANDROID_HOST_BUILD/usr/* $DEST/usr
+ fi
else
- mkdir -p $DEST/com.android.runtime/etc/icu/
- cp -r $ANDROID_HOST_BUILD/com.android.runtime/etc/icu/* $DEST/com.android.runtime/etc/icu/
+ if [ -e $ANDROID_HOST_BUILD/usr/icu ]; then
+ mkdir -p $DEST/usr/icu
+ cp -r $ANDROID_HOST_BUILD/usr/icu/* $DEST/usr/icu
+ else
+ mkdir -p $DEST/com.android.runtime/etc/icu/
+ cp -r $ANDROID_HOST_BUILD/com.android.runtime/etc/icu/* $DEST/com.android.runtime/etc/icu/
+ fi
fi
# Update links for vdex files for Android P and later.
@@ -166,3 +187,4 @@
echo "Now run"
echo "(cd $DEST_ROOT; upload_to_google_storage.py -a --bucket r8-deps $ART_DIR)"
+echo "NOTE; If $ART_DIR has several directory elements adjust accordingly."
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index af8aa34..e7efbfa 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -872,6 +872,7 @@
internal.enableClassStaticizer = false;
internal.outline.enabled = false;
internal.enableEnumUnboxing = false;
+ internal.callSiteOptimizationOptions().disableOptimization();
}
if (!internal.isShrinking()) {
diff --git a/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java b/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java
index 7bf11e0..524b6bc 100644
--- a/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java
+++ b/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java
@@ -25,6 +25,7 @@
builder.addProgramFile(Paths.get(arg));
}
InternalOptions options = new InternalOptions();
+ options.testing.verifyInputs = true;
DexApplication dexApplication =
new ApplicationReader(builder.build(), options, Timing.empty()).read();
AppView<AppInfo> appView = AppView.createForD8(AppInfo.createInitialAppInfo(dexApplication));
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 31d40bb..b231b6e 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -142,6 +142,11 @@
if (shouldDump) {
dumpApplication();
}
+
+ if (options.testing.verifyInputs) {
+ inputApp.validateInputs();
+ }
+
timing.begin("DexApplication.read");
final LazyLoadedDexApplication.Builder builder =
DexApplication.builder(options, timing, resolver);
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 e6db3e1..30a1c04 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -688,15 +688,21 @@
}
public MethodResolutionResult resolveMethodOnClass(DexMethod method, DexClass clazz) {
+ return resolveMethodOnClass(clazz, method.getProto(), method.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnClass(
+ DexClass clazz, DexProto methodProto, DexString methodName) {
assert checkIfObsolete();
assert !clazz.isInterface();
// Step 2:
- MethodResolutionResult result = resolveMethodOnClassStep2(clazz, method, clazz);
+ MethodResolutionResult result =
+ resolveMethodOnClassStep2(clazz, methodProto, methodName, clazz);
if (result != null) {
return result;
}
// Finally Step 3:
- return resolveMethodStep3(clazz, method);
+ return resolveMethodStep3(clazz, methodProto, methodName);
}
/**
@@ -705,16 +711,19 @@
* 5.4.3.3 of the JVM Spec</a>.
*/
private MethodResolutionResult resolveMethodOnClassStep2(
- DexClass clazz, DexMethod method, DexClass initialResolutionHolder) {
+ DexClass clazz,
+ DexProto methodProto,
+ DexString methodName,
+ DexClass initialResolutionHolder) {
// Pt. 1: Signature polymorphic method check.
// See also <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9">
// Section 2.9 of the JVM Spec</a>.
- DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(method.name, dexItemFactory());
+ DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(methodName, dexItemFactory());
if (result != null) {
return new SingleResolutionResult(initialResolutionHolder, clazz, result);
}
// Pt 2: Find a method that matches the descriptor.
- result = clazz.lookupMethod(method);
+ result = clazz.lookupMethod(methodProto, methodName);
if (result != null) {
// If the resolved method is private, then it can only be accessed if the symbolic reference
// that initiated the resolution was the type at which the method resolved on. If that is not
@@ -730,7 +739,8 @@
if (clazz.superType != null) {
DexClass superClass = definitionFor(clazz.superType);
if (superClass != null) {
- return resolveMethodOnClassStep2(superClass, method, initialResolutionHolder);
+ return resolveMethodOnClassStep2(
+ superClass, methodProto, methodName, initialResolutionHolder);
}
}
return null;
@@ -742,35 +752,45 @@
* 5.4.3.3 of the JVM Spec</a>. As this is the same for interfaces and classes, we share one
* implementation.
*/
- private MethodResolutionResult resolveMethodStep3(DexClass clazz, DexMethod method) {
+ private MethodResolutionResult resolveMethodStep3(
+ DexClass clazz, DexProto methodProto, DexString methodName) {
MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder();
- resolveMethodStep3Helper(method, clazz, builder);
+ resolveMethodStep3Helper(methodProto, methodName, clazz, builder);
return builder.resolve(clazz);
}
// Non-private lookup (ie, not resolution) to find interface targets.
DexClassAndMethod lookupMaximallySpecificTarget(DexClass clazz, DexMethod method) {
MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder();
- resolveMethodStep3Helper(method, clazz, builder);
+ resolveMethodStep3Helper(method.getProto(), method.getName(), clazz, builder);
return builder.lookup();
}
// Non-private lookup (ie, not resolution) to find interface targets.
DexClassAndMethod lookupMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) {
MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder();
- resolveMethodStep3Helper(method, dexItemFactory().objectType, lambda.interfaces, builder);
+ resolveMethodStep3Helper(
+ method.getProto(),
+ method.getName(),
+ dexItemFactory().objectType,
+ lambda.interfaces,
+ builder);
return builder.lookup();
}
/** Helper method that builds the set of maximally specific methods. */
private void resolveMethodStep3Helper(
- DexMethod method, DexClass clazz, MaximallySpecificMethodsBuilder builder) {
+ DexProto methodProto,
+ DexString methodName,
+ DexClass clazz,
+ MaximallySpecificMethodsBuilder builder) {
resolveMethodStep3Helper(
- method, clazz.superType, Arrays.asList(clazz.interfaces.values), builder);
+ methodProto, methodName, clazz.superType, Arrays.asList(clazz.interfaces.values), builder);
}
private void resolveMethodStep3Helper(
- DexMethod method,
+ DexProto methodProto,
+ DexString methodName,
DexType superType,
List<DexType> interfaces,
MaximallySpecificMethodsBuilder builder) {
@@ -781,20 +801,20 @@
continue;
}
assert definition.isInterface();
- DexEncodedMethod result = definition.lookupMethod(method);
+ DexEncodedMethod result = definition.lookupMethod(methodProto, methodName);
if (isMaximallySpecificCandidate(result)) {
// The candidate is added and doing so will prohibit shadowed methods from being in the set.
builder.addCandidate(definition, result, this);
} else {
// Look at the super-interfaces of this class and keep searching.
- resolveMethodStep3Helper(method, definition, builder);
+ resolveMethodStep3Helper(methodProto, methodName, definition, builder);
}
}
// Now look at indirect super interfaces.
if (superType != null) {
DexClass superClass = definitionFor(superType);
if (superClass != null) {
- resolveMethodStep3Helper(method, superClass, builder);
+ resolveMethodStep3Helper(methodProto, methodName, superClass, builder);
}
}
}
@@ -860,7 +880,7 @@
}
// Step 3: Look for maximally-specific superinterface methods or any interface definition.
// This is the same for classes and interfaces.
- return resolveMethodStep3(definition, desc);
+ return resolveMethodStep3(definition, desc.getProto(), desc.getName());
}
/**
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 0213b0e..0a7c0e5 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -741,15 +741,20 @@
firstLabel = new CfLabel();
newInstructions.add(firstLabel);
}
- newInstructions.add(new CfPosition(firstLabel, callerPosition));
+ boolean seenPosition = false;
for (CfInstruction instruction : instructions) {
if (instruction.isPosition()) {
+ seenPosition = true;
CfPosition oldPosition = instruction.asPosition();
newInstructions.add(
new CfPosition(
oldPosition.getLabel(),
oldPosition.getPosition().withOutermostCallerPosition(callerPosition)));
} else {
+ if (!instruction.isLabel() && !seenPosition) {
+ newInstructions.add(new CfPosition(firstLabel, callerPosition));
+ seenPosition = true;
+ }
newInstructions.add(instruction);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
index 9cb4704..3aa03da 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -102,6 +102,14 @@
return application.getCallSite(name, desc, bootstrapMethod, bootstrapArgs);
}
+ public List<DexValue> getBootstrapArgs() {
+ return bootstrapArgs;
+ }
+
+ public DexProto getMethodProto() {
+ return methodProto;
+ }
+
@Override
public DexCallSite self() {
return this;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index e4d00aa..d3a63f6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -588,6 +588,10 @@
return methodCollection.getMethod(method);
}
+ public DexEncodedMethod lookupMethod(DexProto methodProto, DexString methodName) {
+ return methodCollection.getMethod(methodProto, methodName);
+ }
+
/** Find method in this class matching {@param method}. */
public DexEncodedMethod lookupMethod(Predicate<DexEncodedMethod> predicate) {
return methodCollection.getMethod(predicate);
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 6daff01..2b8a186 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
@@ -17,7 +16,6 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo;
import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
@@ -45,7 +43,7 @@
/** Generic signature information if the attribute is present in the input */
private FieldTypeSignature genericSignature;
- private FieldOptimizationInfo optimizationInfo;
+ private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
private KotlinFieldLevelInfo kotlinMemberInfo = getNoKotlinInfo();
private static void specify(StructuralSpecification<DexEncodedField, ?> spec) {
@@ -98,20 +96,11 @@
boolean deprecated,
boolean d8R8Synthesized,
AndroidApiLevel apiLevel) {
- super(field, annotations, d8R8Synthesized);
+ super(field, annotations, d8R8Synthesized, apiLevel);
this.accessFlags = accessFlags;
this.staticValue = staticValue;
this.deprecated = deprecated;
this.genericSignature = genericSignature;
- if (apiLevel == AndroidApiLevel.UNKNOWN) {
- optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
- } else if (apiLevel == MIN_API_LEVEL) {
- optimizationInfo = DefaultFieldOptimizationWithMinApiInfo.getInstance();
- } else {
- MutableFieldOptimizationInfo optimizationInfo = new MutableFieldOptimizationInfo();
- this.optimizationInfo = optimizationInfo;
- optimizationInfo.setApiReferenceLevelForDefinition(apiLevel);
- }
assert genericSignature != null;
assert GenericSignatureUtils.verifyNoDuplicateGenericDefinitions(genericSignature, annotations);
}
@@ -148,8 +137,8 @@
}
@Override
- public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) {
- return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel);
+ public AndroidApiLevel getApiLevel() {
+ return getApiLevelForDefinition();
}
public synchronized MutableFieldOptimizationInfo getMutableOptimizationInfo() {
@@ -162,10 +151,6 @@
optimizationInfo = info;
}
- public void setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo info) {
- optimizationInfo = info;
- }
-
@Override
public KotlinFieldLevelInfo getKotlinInfo() {
return kotlinMemberInfo;
@@ -400,6 +385,7 @@
private FieldAccessFlags accessFlags;
private FieldTypeSignature genericSignature;
private DexValue staticValue;
+ private AndroidApiLevel apiLevel;
private FieldOptimizationInfo optimizationInfo;
private boolean deprecated;
private boolean d8R8Synthesized;
@@ -413,6 +399,7 @@
genericSignature = from.getGenericSignature();
annotations = from.annotations();
staticValue = from.staticValue;
+ apiLevel = from.getApiLevel();
optimizationInfo =
from.optimizationInfo.isMutableOptimizationInfo()
? from.optimizationInfo.asMutableFieldOptimizationInfo().mutableCopy()
@@ -468,7 +455,7 @@
staticValue,
deprecated,
d8R8Synthesized,
- AndroidApiLevel.UNKNOWN);
+ apiLevel);
dexEncodedField.optimizationInfo = optimizationInfo;
buildConsumer.accept(dexEncodedField);
return dexEncodedField;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
index c1ce2f5..da3c5ff 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -20,12 +20,20 @@
// set.
private final boolean d8R8Synthesized;
+ /** apiLevelForDefinition describes the api level needed for knowing all types */
+ private AndroidApiLevel apiLevelForDefinition;
+
private final R reference;
- public DexEncodedMember(R reference, DexAnnotationSet annotations, boolean d8R8Synthesized) {
+ public DexEncodedMember(
+ R reference,
+ DexAnnotationSet annotations,
+ boolean d8R8Synthesized,
+ AndroidApiLevel apiLevelForDefinition) {
super(annotations);
this.reference = reference;
this.d8R8Synthesized = d8R8Synthesized;
+ this.apiLevelForDefinition = apiLevelForDefinition;
}
public abstract KotlinMemberLevelInfo getKotlinInfo();
@@ -85,7 +93,15 @@
public abstract MemberOptimizationInfo<?> getOptimizationInfo();
- public abstract AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel);
+ public abstract AndroidApiLevel getApiLevel();
+
+ public AndroidApiLevel getApiLevelForDefinition() {
+ return apiLevelForDefinition;
+ }
+
+ public void setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) {
+ this.apiLevelForDefinition = apiLevelForDefinition;
+ }
@Override
public final boolean equals(Object other) {
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 cb44ff9..c2b204e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -11,7 +11,6 @@
import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL;
import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
import com.android.tools.r8.cf.CfVersion;
@@ -57,7 +56,6 @@
import com.android.tools.r8.ir.optimize.NestUtils;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
@@ -158,9 +156,12 @@
// TODO(b/128967328): towards finer-grained inlining constraints,
// we need to maintain a set of states with (potentially different) contexts.
private CompilationState compilationState = CompilationState.NOT_PROCESSED;
- private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.DEFAULT_INSTANCE;
+ private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
private CallSiteOptimizationInfo callSiteOptimizationInfo = CallSiteOptimizationInfo.bottom();
private CfVersion classFileVersion;
+ /** The apiLevelForCode describes the api level needed for knowing all references in the code */
+ private AndroidApiLevel apiLevelForCode;
+
private KotlinMethodLevelInfo kotlinMemberInfo = getNoKotlinInfo();
/** Generic signature information if the attribute is present in the input */
private MethodTypeSignature genericSignature;
@@ -316,28 +317,18 @@
AndroidApiLevel apiLevelForDefinition,
AndroidApiLevel apiLevelForCode,
boolean deprecated) {
- super(method, annotations, d8R8Synthesized);
+ super(method, annotations, d8R8Synthesized, apiLevelForDefinition);
this.accessFlags = accessFlags;
this.deprecated = deprecated;
this.genericSignature = genericSignature;
this.parameterAnnotationsList = parameterAnnotationsList;
this.code = code;
this.classFileVersion = classFileVersion;
- if (apiLevelForDefinition == AndroidApiLevel.UNKNOWN
- && apiLevelForCode == AndroidApiLevel.UNKNOWN) {
- optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
- } else if (apiLevelForDefinition == MIN_API_LEVEL && apiLevelForCode == MIN_API_LEVEL) {
- optimizationInfo = DefaultMethodOptimizationWithMinApiInfo.getInstance();
- } else {
- MutableMethodOptimizationInfo optimizationInfo =
- DefaultMethodOptimizationInfo.getInstance().toMutableOptimizationInfo();
- optimizationInfo.setApiReferenceLevelForDefinition(apiLevelForDefinition);
- optimizationInfo.setApiReferenceLevelForCode(apiLevelForCode);
- this.optimizationInfo = optimizationInfo;
- }
+ this.apiLevelForCode = apiLevelForCode;
assert accessFlags != null;
assert code == null || !shouldNotHaveCode();
assert parameterAnnotationsList != null;
+ assert apiLevelForCode != null && apiLevelForDefinition != null;
}
public static DexEncodedMethod toMethodDefinitionOrNull(DexClassAndMethod method) {
@@ -1117,11 +1108,17 @@
}
public DexEncodedMethod toMethodThatLogsError(AppView<?> appView) {
- if (appView.options().isGeneratingDex()) {
- return toMethodThatLogsErrorDexCode(appView.dexItemFactory());
- } else {
- return toMethodThatLogsErrorCfCode(appView.dexItemFactory());
- }
+ Builder builder =
+ builder(this)
+ .setCode(
+ appView.options().isGeneratingClassFiles()
+ ? toCfCodeThatLogsError(appView.dexItemFactory())
+ : toDexCodeThatLogsError(appView.dexItemFactory()))
+ .setIsLibraryMethodOverrideIf(
+ belongsToVirtualPool() && !isLibraryMethodOverride().isUnknown(),
+ isLibraryMethodOverride());
+ setObsolete();
+ return builder.build();
}
public static void setDebugInfoWithFakeThisParameter(Code code, int arity, AppView<?> appView) {
@@ -1136,8 +1133,8 @@
cfCode.addFakeThisParameter(appView.dexItemFactory());
}
}
-
- private DexEncodedMethod toMethodThatLogsErrorDexCode(DexItemFactory itemFactory) {
+
+ private DexCode toDexCodeThatLogsError(DexItemFactory itemFactory) {
checkIfObsolete();
Signature signature = MethodSignature.fromDexMethod(getReference());
DexString message =
@@ -1158,23 +1155,18 @@
exceptionType,
itemFactory.createProto(itemFactory.voidType, itemFactory.stringType),
itemFactory.constructorMethodName);
- DexCode code =
- generateCodeFromTemplate(
- 2,
- 2,
- new ConstString(0, tag),
- new ConstString(1, message),
- new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0),
- new NewInstance(0, exceptionType),
- new InvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0),
- new Throw(0));
- Builder builder = builder(this);
- builder.setCode(code);
- setObsolete();
- return builder.build();
+ return generateCodeFromTemplate(
+ 2,
+ 2,
+ new ConstString(0, tag),
+ new ConstString(1, message),
+ new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0),
+ new NewInstance(0, exceptionType),
+ new InvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0),
+ new Throw(0));
}
- private DexEncodedMethod toMethodThatLogsErrorCfCode(DexItemFactory itemFactory) {
+ private CfCode toCfCodeThatLogsError(DexItemFactory itemFactory) {
checkIfObsolete();
Signature signature = MethodSignature.fromDexMethod(getReference());
DexString message =
@@ -1219,18 +1211,13 @@
.add(new CfConstString(message))
.add(new CfInvoke(Opcodes.INVOKESPECIAL, exceptionInitMethod, false))
.add(new CfThrow());
- CfCode code =
- new CfCode(
- getReference().holder,
- 3,
- locals,
- instructionBuilder.build(),
- Collections.emptyList(),
- Collections.emptyList());
- Builder builder = builder(this);
- builder.setCode(code);
- setObsolete();
- return builder.build();
+ return new CfCode(
+ getReference().holder,
+ 3,
+ locals,
+ instructionBuilder.build(),
+ Collections.emptyList(),
+ Collections.emptyList());
}
public DexEncodedMethod toTypeSubstitutedMethod(DexMethod method) {
@@ -1328,7 +1315,10 @@
.getHolderType()
.isInterface(definitions)))
.build())
- .modifyAccessFlags(MethodAccessFlags::setBridge))
+ .modifyAccessFlags(MethodAccessFlags::setBridge)
+ .setIsLibraryMethodOverrideIf(
+ !isStatic() && !isLibraryMethodOverride().isUnknown(),
+ isLibraryMethodOverride()))
.build();
}
@@ -1431,18 +1421,19 @@
return optimizationInfo;
}
- public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApiLevel) {
- return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel);
+ public AndroidApiLevel getApiLevelForCode() {
+ return apiLevelForCode;
}
- public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApiLevel) {
- return optimizationInfo.getApiReferenceLevelForCode(minApiLevel);
+ public void setApiLevelForCode(AndroidApiLevel apiLevel) {
+ assert apiLevel != null;
+ this.apiLevelForCode = apiLevel;
}
@Override
- public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) {
- return getApiReferenceLevelForDefinition(minApiLevel)
- .max(getApiReferenceLevelForCode(minApiLevel));
+ public AndroidApiLevel getApiLevel() {
+ return (isAbstract() ? AndroidApiLevel.B : getApiLevelForCode())
+ .max(getApiLevelForDefinition());
}
public synchronized MutableMethodOptimizationInfo getMutableOptimizationInfo() {
@@ -1457,11 +1448,6 @@
optimizationInfo = info;
}
- public void setMinApiOptimizationInfo(DefaultMethodOptimizationWithMinApiInfo info) {
- checkIfObsolete();
- optimizationInfo = info;
- }
-
public synchronized void abandonCallSiteOptimizationInfo() {
checkIfObsolete();
callSiteOptimizationInfo = CallSiteOptimizationInfo.abandoned();
@@ -1525,6 +1511,8 @@
private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
private KotlinMethodLevelInfo kotlinInfo = getNoKotlinInfo();
private CfVersion classFileVersion = null;
+ private AndroidApiLevel apiLevelForDefinition = null;
+ private AndroidApiLevel apiLevelForCode = null;
private boolean d8R8Synthesized = false;
private Consumer<DexEncodedMethod> buildConsumer = ConsumerUtils.emptyConsumer();
@@ -1542,6 +1530,8 @@
genericSignature = from.getGenericSignature();
annotations = from.annotations();
code = from.getCode();
+ apiLevelForDefinition = from.getApiLevelForDefinition();
+ apiLevelForCode = from.getApiLevelForCode();
optimizationInfo =
from.getOptimizationInfo().isMutableOptimizationInfo()
? from.getOptimizationInfo().asMutableMethodOptimizationInfo().mutableCopy()
@@ -1732,6 +1722,8 @@
assert parameterAnnotations != null;
assert parameterAnnotations.isEmpty()
|| parameterAnnotations.size() == method.proto.parameters.size();
+ assert apiLevelForDefinition != null;
+ assert apiLevelForCode != null;
DexEncodedMethod result =
new DexEncodedMethod(
method,
@@ -1742,8 +1734,8 @@
code,
d8R8Synthesized,
classFileVersion,
- AndroidApiLevel.UNKNOWN,
- AndroidApiLevel.UNKNOWN);
+ apiLevelForDefinition,
+ apiLevelForCode);
result.setKotlinMemberInfo(kotlinInfo);
result.compilationState = compilationState;
result.optimizationInfo = optimizationInfo;
@@ -1758,5 +1750,15 @@
this.genericSignature = methodSignature;
return this;
}
+
+ public Builder setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) {
+ this.apiLevelForDefinition = apiLevelForDefinition;
+ return this;
+ }
+
+ public Builder setApiLevelForCode(AndroidApiLevel apiLevelForCode) {
+ this.apiLevelForCode = apiLevelForCode;
+ return this;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index 5a109e7..c5cb0ff 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -228,7 +228,15 @@
@Override
public boolean match(DexMethod method) {
- return method.name == name && method.proto == proto;
+ return match(method.getProto(), method.getName());
+ }
+
+ public boolean match(DexMethodSignature method) {
+ return match(method.getProto(), method.getName());
+ }
+
+ public boolean match(DexProto methodProto, DexString methodName) {
+ return proto == methodProto && name == methodName;
}
@Override
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 8b2fcc4..74d464f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
@@ -4,9 +4,13 @@
package com.android.tools.r8.graph;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Objects;
-public class DexMethodSignature {
+public class DexMethodSignature implements StructuralItem<DexMethodSignature> {
+
private final DexProto proto;
private final DexString name;
@@ -21,14 +25,31 @@
this.name = name;
}
- public DexProto getProto() {
- return proto;
+ public int getArity() {
+ return proto.getArity();
}
public DexString getName() {
return name;
}
+ public DexProto getProto() {
+ return proto;
+ }
+
+ public DexType getReturnType() {
+ return proto.returnType;
+ }
+
+ @Override
+ public StructuralMapping<DexMethodSignature> getStructuralMapping() {
+ return DexMethodSignature::specify;
+ }
+
+ private static void specify(StructuralSpecification<DexMethodSignature, ?> spec) {
+ spec.withItem(DexMethodSignature::getName).withItem(DexMethodSignature::getProto);
+ }
+
public DexMethodSignature withName(DexString name) {
return new DexMethodSignature(proto, name);
}
@@ -58,12 +79,9 @@
return Objects.hash(proto, name);
}
- public DexType getReturnType() {
- return proto.returnType;
- }
-
- public int getArity() {
- return proto.getArity();
+ @Override
+ public DexMethodSignature self() {
+ return this;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 8a3f39a..e297bd4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.graph;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
import static com.google.common.base.Predicates.alwaysTrue;
import com.android.tools.r8.ProgramResource;
@@ -827,7 +827,7 @@
AppView<?> appView,
BiFunction<DexReference, AndroidApiLevel, AndroidApiLevel> apiLevelLookup) {
// The api level of a class is the max level of it's members, super class and interfaces.
- AndroidApiLevel computedApiLevel = getApiLevelIfEnabled(appView, Function.identity());
+ AndroidApiLevel computedApiLevel = minApiLevelIfEnabledOrUnknown(appView);
for (DexType superType : allImmediateSupertypes()) {
computedApiLevel = apiLevelLookup.apply(superType, computedApiLevel);
if (computedApiLevel == AndroidApiLevel.UNKNOWN) {
@@ -838,9 +838,9 @@
}
public AndroidApiLevel getMembersApiReferenceLevel(AppView<?> appView) {
- AndroidApiLevel memberLevel = getApiLevelIfEnabled(appView, Function.identity());
+ AndroidApiLevel memberLevel = minApiLevelIfEnabledOrUnknown(appView);
for (DexEncodedMember<?, ?> member : members()) {
- memberLevel = memberLevel.max(getApiLevelIfEnabled(appView, member::getApiReferenceLevel));
+ memberLevel = memberLevel.max(member.getApiLevel());
if (memberLevel == AndroidApiLevel.UNKNOWN) {
return AndroidApiLevel.UNKNOWN;
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
index 62b62b9..03627d7 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
@@ -66,6 +66,10 @@
return false;
}
+ public boolean isFailedResolution() {
+ return false;
+ }
+
public DexClass getInitialResolutionHolder() {
return null;
}
@@ -163,6 +167,11 @@
public boolean isFailedOrUnknownResolution() {
return true;
}
+
+ @Override
+ public boolean isFailedResolution() {
+ return true;
+ }
}
/**
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 8da7519..37dea58 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -681,7 +681,11 @@
continue;
}
DexMethod originalMethod = getOriginalMethodSignature(method.getReference());
- assert originalMethods.contains(originalMethod);
+ assert originalMethods.contains(originalMethod)
+ : "Method could not be mapped back: "
+ + method.toSourceString()
+ + ", originalMethod: "
+ + originalMethod.toSourceString();
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
index ac08e3f..fa003ea 100644
--- a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
@@ -63,6 +63,24 @@
});
}
+ public void forEachImmediateProgramSuperClass(
+ DexProgramClass clazz, Consumer<? super DexProgramClass> consumer) {
+ forEachImmediateProgramSuperClassMatching(clazz, alwaysTrue(), consumer);
+ }
+
+ public void forEachImmediateProgramSuperClassMatching(
+ DexProgramClass clazz,
+ Predicate<? super DexProgramClass> predicate,
+ Consumer<? super DexProgramClass> consumer) {
+ clazz.forEachImmediateSupertype(
+ supertype -> {
+ DexProgramClass superclass = asProgramClassOrNull(appView.definitionFor(supertype));
+ if (superclass != null && predicate.test(superclass)) {
+ consumer.accept(superclass);
+ }
+ });
+ }
+
public void forEachImmediateSubClass(
DexProgramClass clazz, Consumer<? super DexProgramClass> consumer) {
forEachImmediateSubClassMatching(clazz, alwaysTrue(), consumer);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index 7e67c3b..6930912 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -249,9 +249,21 @@
}
@Override
- DexEncodedMethod getMethod(DexMethod method) {
- DexEncodedMethod result = getDirectMethod(method);
- return result == null ? getVirtualMethod(method) : result;
+ DexEncodedMethod getMethod(DexProto methodProto, DexString methodName) {
+ DexEncodedMethod directMethod = internalGetMethod(methodProto, methodName, directMethods);
+ return directMethod == null
+ ? internalGetMethod(methodProto, methodName, virtualMethods)
+ : directMethod;
+ }
+
+ private static DexEncodedMethod internalGetMethod(
+ DexProto methodProto, DexString methodName, DexEncodedMethod[] methods) {
+ for (DexEncodedMethod method : methods) {
+ if (method.getReference().match(methodProto, methodName)) {
+ return method;
+ }
+ }
+ return null;
}
@Override
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 3509b8c..3dc2b58 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -160,7 +160,11 @@
}
public DexEncodedMethod getMethod(DexMethod method) {
- return backing.getMethod(method);
+ return backing.getMethod(method.getProto(), method.getName());
+ }
+
+ public DexEncodedMethod getMethod(DexProto methodProto, DexString methodName) {
+ return backing.getMethod(methodProto, methodName);
}
public DexEncodedMethod getMethod(Predicate<DexEncodedMethod> predicate) {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
index 301352a..90fbf1f 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
@@ -68,7 +68,7 @@
// Lookup methods.
- abstract DexEncodedMethod getMethod(DexMethod method);
+ abstract DexEncodedMethod getMethod(DexProto methodProto, DexString methodName);
abstract DexEncodedMethod getDirectMethod(DexMethod method);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
index a7d3c45..8f705d4 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
@@ -5,67 +5,59 @@
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.IteratorUtils;
-import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.TraversalContinuation;
-import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.Lists;
-import it.unimi.dsi.fastutil.objects.Object2ReferenceLinkedOpenHashMap;
-import it.unimi.dsi.fastutil.objects.Object2ReferenceMap;
-import it.unimi.dsi.fastutil.objects.Object2ReferenceRBTreeMap;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.TreeMap;
import java.util.function.Function;
import java.util.function.Predicate;
public class MethodMapBacking extends MethodCollectionBacking {
- private Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> methodMap;
+ private Map<DexMethodSignature, DexEncodedMethod> methodMap;
public MethodMapBacking() {
this(createMap());
}
- private MethodMapBacking(Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> methodMap) {
+ private MethodMapBacking(Map<DexMethodSignature, DexEncodedMethod> methodMap) {
this.methodMap = methodMap;
}
public static MethodMapBacking createSorted() {
- Comparator<Wrapper<DexMethod>> comparator = Comparator.comparing(Wrapper::get);
- return new MethodMapBacking(new Object2ReferenceRBTreeMap<>(comparator));
+ return new MethodMapBacking(new TreeMap<>());
}
- private static Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> createMap() {
+ private static Map<DexMethodSignature, DexEncodedMethod> createMap() {
// Maintain a linked map so the output order remains a deterministic function of the input.
- return new Object2ReferenceLinkedOpenHashMap<>();
+ return new HashMap<>();
}
- private static Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> createMap(int capacity) {
+ private static Map<DexMethodSignature, DexEncodedMethod> createMap(int capacity) {
// Maintain a linked map so the output order remains a deterministic function of the input.
- return new Object2ReferenceLinkedOpenHashMap<>(capacity);
+ return new HashMap<>(capacity);
}
- private Wrapper<DexMethod> wrap(DexMethod method) {
- return MethodSignatureEquivalence.get().wrap(method);
- }
-
- private void replace(Wrapper<DexMethod> existingKey, DexEncodedMethod method) {
- if (existingKey.get().match(method)) {
+ private void replace(DexMethodSignature existingKey, DexEncodedMethod method) {
+ if (method.getReference().match(existingKey)) {
methodMap.put(existingKey, method);
} else {
methodMap.remove(existingKey);
- methodMap.put(wrap(method.getReference()), method);
+ methodMap.put(method.getSignature(), method);
}
}
@Override
boolean verify() {
methodMap.forEach(
- (key, method) -> {
- assert key.get().match(method);
+ (signature, method) -> {
+ assert method.getReference().match(signature);
});
return true;
}
@@ -97,7 +89,7 @@
@Override
TraversalContinuation traverse(Function<DexEncodedMethod, TraversalContinuation> fn) {
- for (Entry<Wrapper<DexMethod>, DexEncodedMethod> entry : methodMap.object2ReferenceEntrySet()) {
+ for (Entry<DexMethodSignature, DexEncodedMethod> entry : methodMap.entrySet()) {
TraversalContinuation result = fn.apply(entry.getValue());
if (result.shouldBreak()) {
return result;
@@ -122,8 +114,8 @@
}
@Override
- DexEncodedMethod getMethod(DexMethod method) {
- return methodMap.get(wrap(method));
+ DexEncodedMethod getMethod(DexProto methodProto, DexString methodName) {
+ return methodMap.get(new DexMethodSignature(methodProto, methodName));
}
private DexEncodedMethod getMethod(Predicate<DexEncodedMethod> predicate) {
@@ -141,7 +133,7 @@
@Override
DexEncodedMethod getDirectMethod(DexMethod method) {
- DexEncodedMethod definition = getMethod(method);
+ DexEncodedMethod definition = getMethod(method.getProto(), method.getName());
return definition != null && belongsToDirectPool(definition) ? definition : null;
}
@@ -153,7 +145,7 @@
@Override
DexEncodedMethod getVirtualMethod(DexMethod method) {
- DexEncodedMethod definition = getMethod(method);
+ DexEncodedMethod definition = getMethod(method.getProto(), method.getName());
return definition != null && belongsToVirtualPool(definition) ? definition : null;
}
@@ -165,7 +157,7 @@
@Override
void addMethod(DexEncodedMethod method) {
- Wrapper<DexMethod> key = wrap(method.getReference());
+ DexMethodSignature key = method.getSignature();
DexEncodedMethod old = methodMap.put(key, method);
assert old == null;
}
@@ -208,12 +200,12 @@
@Override
DexEncodedMethod removeMethod(DexMethod method) {
- return methodMap.remove(wrap(method));
+ return methodMap.remove(method.getSignature());
}
@Override
void removeMethods(Set<DexEncodedMethod> methods) {
- methods.forEach(method -> methodMap.remove(wrap(method.getReference())));
+ methods.forEach(method -> methodMap.remove(method.getSignature()));
}
@Override
@@ -224,17 +216,16 @@
if (methods == null) {
methods = DexEncodedMethod.EMPTY_ARRAY;
}
- Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> newMap =
- createMap(size() + methods.length);
+ Map<DexMethodSignature, DexEncodedMethod> newMap = createMap(size() + methods.length);
forEachMethod(
method -> {
if (belongsToVirtualPool(method)) {
- newMap.put(wrap(method.getReference()), method);
+ newMap.put(method.getSignature(), method);
}
});
for (DexEncodedMethod method : methods) {
assert belongsToDirectPool(method);
- newMap.put(wrap(method.getReference()), method);
+ newMap.put(method.getSignature(), method);
}
methodMap = newMap;
}
@@ -247,17 +238,16 @@
if (methods == null) {
methods = DexEncodedMethod.EMPTY_ARRAY;
}
- Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> newMap =
- createMap(size() + methods.length);
+ Map<DexMethodSignature, DexEncodedMethod> newMap = createMap(size() + methods.length);
forEachMethod(
method -> {
if (belongsToDirectPool(method)) {
- newMap.put(wrap(method.getReference()), method);
+ newMap.put(method.getSignature(), method);
}
});
for (DexEncodedMethod method : methods) {
assert belongsToVirtualPool(method);
- newMap.put(wrap(method.getReference()), method);
+ newMap.put(method.getSignature(), method);
}
methodMap = newMap;
}
@@ -325,7 +315,7 @@
DexMethod method,
Function<DexEncodedMethod, DexEncodedMethod> replacement,
Predicate<DexEncodedMethod> predicate) {
- Wrapper<DexMethod> key = wrap(method);
+ DexMethodSignature key = method.getSignature();
DexEncodedMethod existing = methodMap.get(key);
if (existing == null || !predicate.test(existing)) {
return null;
@@ -339,7 +329,7 @@
@Override
DexEncodedMethod replaceDirectMethodWithVirtualMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
- Wrapper<DexMethod> key = wrap(method);
+ DexMethodSignature key = method.getSignature();
DexEncodedMethod existing = methodMap.get(key);
if (existing == null || belongsToVirtualPool(existing)) {
return null;
@@ -359,7 +349,7 @@
private boolean verifyVirtualizedMethods(Set<DexEncodedMethod> methods) {
for (DexEncodedMethod method : methods) {
assert belongsToVirtualPool(method);
- assert methodMap.get(wrap(method.getReference())) == method;
+ assert methodMap.get(method.getSignature()) == method;
}
return true;
}
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 aadd446..f1e8ae1 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -80,6 +80,10 @@
return false;
}
+ public boolean isClassNotFoundResult() {
+ return false;
+ }
+
/** Returns non-null if isFailedResolution() is true, otherwise null. */
public FailedResolutionResult asFailedResolution() {
return null;
@@ -94,6 +98,10 @@
return null;
}
+ public ProgramMethod getResolvedProgramMethod() {
+ return null;
+ }
+
@Override
public DexClassAndMethod getResolutionPair() {
return null;
@@ -188,6 +196,7 @@
return resolvedMethod;
}
+ @Override
public ProgramMethod getResolvedProgramMethod() {
return resolvedHolder.isProgramClass()
? new ProgramMethod(resolvedHolder.asProgramClass(), resolvedMethod)
@@ -846,6 +855,11 @@
private ClassNotFoundResult() {
// Intentionally left empty.
}
+
+ @Override
+ public boolean isClassNotFoundResult() {
+ return true;
+ }
}
public abstract static class FailedResolutionWithCausingMethods extends FailedResolutionResult {
diff --git a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
index d09c3f5..f3670f3 100644
--- a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
+++ b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
@@ -208,7 +208,10 @@
// inner class attributes.
boolean innerClassAttributeChanged =
newInnerClassType != innerClassType || newOuterClassType != outerClassType;
- if (innerClassAttributeChanged && innerClassType != null && outerClassType != null) {
+ if (innerClassAttributeChanged
+ && innerClassType != null
+ && outerClassType != null
+ && innerClassAttribute.getInnerName() != null) {
String innerClassName =
DescriptorUtils.getInnerClassName(
newOuterClassType.toDescriptorString(), newInnerClassType.toDescriptorString());
@@ -217,10 +220,8 @@
} else {
// If run without treeshaking and the outer type is missing we are not pruning the
// relationship.
- // TODO(b/196503304): Enable the below asserts when resolved.
- assert !appView.options().isTreeShakingEnabled() || true;
- // assert appView.appInfo().definitionForWithoutExistenceAssert(newOuterClassType) ==
- // null;
+ assert !appView.options().isTreeShakingEnabled();
+ assert appView.appInfo().definitionForWithoutExistenceAssert(newOuterClassType) == null;
}
}
newInnerClassAttributes.add(
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index b4615df..9da5368 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -6,18 +6,11 @@
import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMember;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.LookupTarget;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo;
-import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -35,14 +28,12 @@
@Override
public void processNewlyLiveField(ProgramField field, ProgramDefinition context) {
- setApiLevelForMemberDefinition(
- field.getDefinition(), computeApiLevelForReferencedTypes(field.getReference()));
+ computeApiLevelForDefinition(field);
}
@Override
public void processNewlyLiveMethod(ProgramMethod method, ProgramDefinition context) {
- setApiLevelForMemberDefinition(
- method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference()));
+ computeApiLevelForDefinition(method);
}
@Override
@@ -55,71 +46,35 @@
.tracedMethodApiLevelCallback
.accept(method.getMethodReference(), registry.getMaxApiReferenceLevel());
}
- setApiLevelForMemberDefinition(
- method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference()));
- setApiLevelForCode(method.getDefinition(), registry.getMaxApiReferenceLevel());
+ computeApiLevelForDefinition(method);
+ method.getDefinition().setApiLevelForCode(registry.getMaxApiReferenceLevel());
}
@Override
public void notifyMarkMethodAsTargeted(ProgramMethod method) {
- setApiLevelForMemberDefinition(method.getDefinition(), minApiLevel);
+ computeApiLevelForDefinition(method);
}
@Override
public void notifyMarkFieldAsReachable(ProgramField field) {
- setApiLevelForMemberDefinition(field.getDefinition(), minApiLevel);
+ computeApiLevelForDefinition(field);
}
@Override
public void notifyMarkVirtualDispatchTargetAsLive(LookupTarget target) {
target.accept(
- dexClassAndMethod -> {
- setApiLevelForMemberDefinition(dexClassAndMethod.getDefinition(), minApiLevel);
- },
+ this::computeApiLevelForDefinition,
lookupLambdaTarget -> {
// The implementation method will be assigned an api level when visited.
});
}
- private void setApiLevelForMemberDefinition(
- DexEncodedMember<?, ?> member, AndroidApiLevel apiLevel) {
- // To not have mutable update information for all members that all has min api level we
- // swap the default optimization info for one with that marks the api level to be min api.
- MemberOptimizationInfo<?> optimizationInfo = member.getOptimizationInfo();
- if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) {
- member.accept(
- field -> {
- field.setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo.getInstance());
- },
- method -> {
- method.setMinApiOptimizationInfo(DefaultMethodOptimizationWithMinApiInfo.getInstance());
- });
- } else {
- AndroidApiLevel maxApiLevel =
- optimizationInfo.hasApiReferenceLevelForDefinition()
- ? apiLevel.max(optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel))
- : apiLevel;
- member.accept(
- field -> {
- field.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel);
- },
- method -> {
- method.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel);
- });
- }
- }
-
- private void setApiLevelForCode(DexEncodedMethod method, AndroidApiLevel apiLevel) {
- MethodOptimizationInfo optimizationInfo = method.getOptimizationInfo();
- assert optimizationInfo != DefaultMethodOptimizationInfo.getInstance();
- if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) {
- assert optimizationInfo == DefaultMethodOptimizationWithMinApiInfo.getInstance();
- return;
- }
- method.getMutableOptimizationInfo().setApiReferenceLevelForCode(apiLevel);
- }
-
- private AndroidApiLevel computeApiLevelForReferencedTypes(DexMember<?, ?> member) {
- return member.computeApiLevelForReferencedTypes(appView, referenceLevelCache::lookupMax);
+ private void computeApiLevelForDefinition(DexClassAndMember<?, ?> member) {
+ member
+ .getDefinition()
+ .setApiLevelForDefinition(
+ member
+ .getReference()
+ .computeApiLevelForReferencedTypes(appView, referenceLevelCache::lookupMax));
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index a772278..43a2c8a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.horizontalclassmerging;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
import static com.google.common.base.Predicates.not;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -45,7 +45,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.Function;
/**
* The class merger is responsible for moving methods from the sources in {@link ClassMerger#group}
@@ -141,8 +140,8 @@
classInitializerMerger.getCode(syntheticMethodReference),
DexEncodedMethod.D8_R8_SYNTHESIZED,
classInitializerMerger.getCfVersion(),
- getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel),
- getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel));
+ apiReferenceLevel,
+ apiReferenceLevel);
classMethodsBuilder.addDirectMethod(definition);
// In case we didn't synthesize CF code, we register the class initializer for conversion to dex
@@ -230,7 +229,7 @@
null,
deprecated,
d8R8Synthesized,
- getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+ minApiLevelIfEnabledOrUnknown(appView));
// For the $r8$classId synthesized fields, we try to over-approximate the set of values it may
// have. For example, for a merge group of size 4, we may compute the set {0, 2, 3}, if the
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index adc89fc..d6ae971 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.horizontalclassmerging;
import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.dex.Constants;
@@ -372,10 +371,8 @@
getNewCode(newMethodReference, syntheticMethodReference, needsClassId, extraNulls),
true,
getNewClassFileVersion(),
- getApiLevelIfEnabledForNewMember(
- appView, representativeMethod::getApiReferenceLevelForDefinition),
- getApiLevelIfEnabledForNewMember(
- appView, representativeMethod::getApiReferenceLevelForCode));
+ representativeMethod.getApiLevelForDefinition(),
+ representativeMethod.getApiLevelForCode());
classMethodsBuilder.addDirectMethod(newInstanceInitializer);
if (mode.isFinal()) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 87a3211..be6a5a2 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.horizontalclassmerging;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
-
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
@@ -289,10 +287,8 @@
synthesizedCode,
true,
classFileVersion,
- getApiLevelIfEnabledForNewMember(
- appView, representativeMethod::getApiReferenceLevelForDefinition),
- getApiLevelIfEnabledForNewMember(
- appView, representativeMethod::getApiReferenceLevelForCode));
+ representativeMethod.getApiLevelForDefinition(),
+ representativeMethod.getApiLevelForCode());
if (!representative.getDefinition().isLibraryMethodOverride().isUnknown()) {
newMethod.setLibraryMethodOverride(representative.getDefinition().isLibraryMethodOverride());
}
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 cff4480..3251db1 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
@@ -4,7 +4,7 @@
package com.android.tools.r8.horizontalclassmerging.code;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
import static java.lang.Integer.max;
import com.android.tools.r8.cf.CfVersion;
@@ -104,12 +104,8 @@
assert !classInitializers.isEmpty();
return ListUtils.fold(
classInitializers,
- appView.options().apiModelingOptions().enableApiCallerIdentification
- ? appView.options().minApiLevel
- : AndroidApiLevel.UNKNOWN,
- (accApiLevel, method) ->
- accApiLevel.max(
- getApiLevelIfEnabled(appView, method.getDefinition()::getApiReferenceLevel)));
+ minApiLevelIfEnabledOrUnknown(appView),
+ (accApiLevel, method) -> accApiLevel.max(method.getDefinition().getApiLevel()));
}
public static class Builder {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
index 083c27f..9e83183 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
@@ -140,6 +140,16 @@
}
@Override
+ public ClassTypeElement joinNullability(Nullability nullability) {
+ return getOrCreateVariant(nullability().join(nullability));
+ }
+
+ @Override
+ public ClassTypeElement meetNullability(Nullability nullability) {
+ return getOrCreateVariant(nullability().meet(nullability));
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(nullability);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
index 12d1c4c..5db6f54 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Objects;
/**
* Represents the runtime type of a reference value. This type may be more precise than the value's
@@ -27,18 +28,40 @@
this.dynamicUpperBoundType = dynamicUpperBoundType;
}
- public static DynamicType create(Value value, AppView<AppInfoWithLiveness> appView) {
- assert value.getType().isReferenceType();
- TypeElement dynamicUpperBoundType = value.getDynamicUpperBoundType(appView);
- ClassTypeElement dynamicLowerBoundType = value.getDynamicLowerBoundType(appView);
+ public static DynamicType create(
+ AppView<AppInfoWithLiveness> appView,
+ TypeElement dynamicUpperBoundType,
+ ClassTypeElement dynamicLowerBoundType) {
+ if (dynamicUpperBoundType.isBottom()) {
+ return bottom();
+ }
+ if (dynamicUpperBoundType.isTop()) {
+ return unknown();
+ }
if (dynamicLowerBoundType != null) {
assert dynamicUpperBoundType.isClassType();
+ assert dynamicUpperBoundType.nullability() == dynamicLowerBoundType.nullability();
+ if (dynamicUpperBoundType.equals(dynamicLowerBoundType)) {
+ return createExact(dynamicLowerBoundType);
+ }
return DynamicTypeWithLowerBound.create(
appView, dynamicUpperBoundType.asClassType(), dynamicLowerBoundType);
}
return new DynamicType(dynamicUpperBoundType);
}
+ public static DynamicType createExact(ClassTypeElement exactDynamicType) {
+ return new ExactDynamicType(exactDynamicType);
+ }
+
+ public static DynamicType create(Value value, AppView<AppInfoWithLiveness> appView) {
+ assert value.getType().isReferenceType();
+ TypeElement dynamicUpperBoundType = value.getDynamicUpperBoundType(appView);
+ ClassTypeElement dynamicLowerBoundType =
+ value.getDynamicLowerBoundType(appView, dynamicUpperBoundType.nullability());
+ return create(appView, dynamicUpperBoundType, dynamicLowerBoundType);
+ }
+
public static DynamicType bottom() {
return BOTTOM;
}
@@ -59,21 +82,61 @@
return null;
}
+ public boolean isBottom() {
+ return getDynamicUpperBoundType().isBottom();
+ }
+
public boolean isTrivial(TypeElement staticType) {
- return staticType == getDynamicUpperBoundType() || isUnknown();
+ return staticType.equals(getDynamicUpperBoundType()) || isUnknown();
}
public boolean isUnknown() {
return getDynamicUpperBoundType().isTop();
}
+ public DynamicType join(AppView<AppInfoWithLiveness> appView, DynamicType dynamicType) {
+ if (isBottom()) {
+ return dynamicType;
+ }
+ if (dynamicType.isBottom() || equals(dynamicType)) {
+ return this;
+ }
+ if (isUnknown() || dynamicType.isUnknown()) {
+ return unknown();
+ }
+ TypeElement upperBoundType =
+ getDynamicUpperBoundType().join(dynamicType.getDynamicUpperBoundType(), appView);
+ ClassTypeElement lowerBoundType = meetDynamicLowerBound(appView, dynamicType);
+ if (upperBoundType.equals(getDynamicUpperBoundType())
+ && Objects.equals(lowerBoundType, getDynamicLowerBoundType())) {
+ return this;
+ }
+ return create(appView, upperBoundType, lowerBoundType);
+ }
+
+ private ClassTypeElement meetDynamicLowerBound(
+ AppView<AppInfoWithLiveness> appView, DynamicType dynamicType) {
+ if (!hasDynamicLowerBoundType() || !dynamicType.hasDynamicLowerBoundType()) {
+ return null;
+ }
+ ClassTypeElement lowerBoundType = getDynamicLowerBoundType();
+ ClassTypeElement otherLowerBoundType = dynamicType.getDynamicLowerBoundType();
+ if (lowerBoundType.lessThanOrEqualUpToNullability(otherLowerBoundType, appView)) {
+ return lowerBoundType.joinNullability(otherLowerBoundType.nullability());
+ }
+ if (otherLowerBoundType.lessThanOrEqualUpToNullability(lowerBoundType, appView)) {
+ return otherLowerBoundType.joinNullability(lowerBoundType.nullability());
+ }
+ return null;
+ }
+
@Override
public boolean equals(Object other) {
if (other == null || getClass() != other.getClass()) {
return false;
}
- DynamicType assumption = (DynamicType) other;
- return dynamicUpperBoundType == assumption.dynamicUpperBoundType;
+ DynamicType dynamicType = (DynamicType) other;
+ return dynamicUpperBoundType.equals(dynamicType.dynamicUpperBoundType);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
index ae61ee3..400f99e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
@@ -15,16 +15,21 @@
DynamicTypeWithLowerBound(
ClassTypeElement dynamicUpperBoundType, ClassTypeElement dynamicLowerBoundType) {
super(dynamicUpperBoundType);
+ assert !dynamicUpperBoundType.equals(dynamicLowerBoundType);
this.dynamicLowerBoundType = dynamicLowerBoundType;
}
- public static DynamicTypeWithLowerBound create(
+ static DynamicTypeWithLowerBound create(
AppView<AppInfoWithLiveness> appView,
ClassTypeElement dynamicUpperBoundType,
ClassTypeElement dynamicLowerBoundType) {
+ assert dynamicUpperBoundType != null;
+ assert dynamicLowerBoundType != null;
+ assert dynamicUpperBoundType.nullability() == dynamicLowerBoundType.nullability();
assert appView
.appInfo()
- .isSubtype(dynamicLowerBoundType.getClassType(), dynamicUpperBoundType.getClassType());
+ .isStrictSubtypeOf(
+ dynamicLowerBoundType.getClassType(), dynamicUpperBoundType.getClassType());
return new DynamicTypeWithLowerBound(dynamicUpperBoundType, dynamicLowerBoundType);
}
@@ -48,9 +53,9 @@
if (other == null || getClass() != other.getClass()) {
return false;
}
- DynamicTypeWithLowerBound assumption = (DynamicTypeWithLowerBound) other;
- return getDynamicUpperBoundType() == assumption.getDynamicUpperBoundType()
- && getDynamicLowerBoundType() == assumption.getDynamicLowerBoundType();
+ DynamicTypeWithLowerBound dynamicType = (DynamicTypeWithLowerBound) other;
+ return getDynamicUpperBoundType().equals(dynamicType.getDynamicUpperBoundType())
+ && getDynamicLowerBoundType().equals(dynamicType.getDynamicLowerBoundType());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
new file mode 100644
index 0000000..a6061d9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2021, 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.analysis.type;
+
+public class ExactDynamicType extends DynamicType {
+
+ ExactDynamicType(ClassTypeElement exactDynamicType) {
+ super(exactDynamicType);
+ }
+
+ @Override
+ public boolean hasDynamicLowerBoundType() {
+ return true;
+ }
+
+ @Override
+ public ClassTypeElement getDynamicLowerBoundType() {
+ return getDynamicUpperBoundType().asClassType();
+ }
+
+ @Override
+ public boolean isTrivial(TypeElement staticType) {
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ ExactDynamicType dynamicType = (ExactDynamicType) other;
+ return getDynamicUpperBoundType().equals(dynamicType.getDynamicUpperBoundType());
+ }
+
+ @Override
+ public int hashCode() {
+ return getDynamicLowerBoundType().hashCode();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java b/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java
index 26b9030..e45ac9a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java
@@ -29,6 +29,10 @@
private Nullability() {}
+ public boolean isBottom() {
+ return this == BOTTOM;
+ }
+
public boolean isDefinitelyNull() {
return this == DEFINITELY_NULL;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
index c150cfd..3577c72 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
@@ -78,6 +78,10 @@
return getOrCreateVariant(nullability.meet(Nullability.definitelyNotNull()));
}
+ public TypeElement asDefinitelyNull() {
+ return getOrCreateVariant(Nullability.definitelyNull());
+ }
+
public TypeElement asDefinitelyNotNull() {
return getOrCreateVariant(Nullability.definitelyNotNull());
}
@@ -86,6 +90,14 @@
return getOrCreateVariant(Nullability.maybeNull());
}
+ public ReferenceTypeElement joinNullability(Nullability nullability) {
+ return getOrCreateVariant(nullability().join(nullability));
+ }
+
+ public ReferenceTypeElement meetNullability(Nullability nullability) {
+ return getOrCreateVariant(nullability().meet(nullability));
+ }
+
@Override
public boolean isReferenceType() {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Assume.java b/src/main/java/com/android/tools/r8/ir/code/Assume.java
index 3a51eec..f25c73b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Assume.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Assume.java
@@ -311,6 +311,8 @@
}
public boolean verifyCorrectnessOfValues(Value dest, Value src, AppView<?> appView) {
+ assert !dynamicUpperBoundType.isBottom();
+ assert !dynamicUpperBoundType.isTop();
assert dynamicUpperBoundType.lessThanOrEqualUpToNullability(src.getType(), appView);
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index ce8efd1..4df7f91 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.graph.ProgramMethod;
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.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
@@ -1136,13 +1137,18 @@
}
public ClassTypeElement getDynamicLowerBoundType(AppView<AppInfoWithLiveness> appView) {
+ return getDynamicLowerBoundType(appView, Nullability.maybeNull());
+ }
+
+ public ClassTypeElement getDynamicLowerBoundType(
+ AppView<AppInfoWithLiveness> appView, Nullability maxNullability) {
// If it is a final or effectively-final class type, then we know the lower bound.
if (getType().isClassType()) {
ClassTypeElement classType = getType().asClassType();
DexType type = classType.getClassType();
DexClass clazz = appView.definitionFor(type);
if (clazz != null && clazz.isEffectivelyFinal(appView)) {
- return classType;
+ return classType.meetNullability(maxNullability);
}
}
@@ -1151,25 +1157,32 @@
return null;
}
- Instruction definition = root.definition;
+ Instruction definition = root.getDefinition();
if (definition.isNewInstance()) {
- DexType type = definition.asNewInstance().clazz;
+ DexType type = definition.asNewInstance().getType();
DexClass clazz = appView.definitionFor(type);
if (clazz != null && !clazz.isInterface()) {
- return ClassTypeElement.create(type, definitelyNotNull(), appView);
+ assert !maxNullability.isBottom();
+ return TypeElement.fromDexType(type, definitelyNotNull(), appView).asClassType();
}
return null;
}
// Try to find an alias of the receiver, which is defined by an instruction of the type Assume.
Value aliasedValue =
- getSpecificAliasedValue(value -> value.definition.isAssumeWithDynamicTypeAssumption());
+ getSpecificAliasedValue(value -> value.getDefinition().isAssumeWithDynamicTypeAssumption());
if (aliasedValue != null) {
- ClassTypeElement lattice =
- aliasedValue.definition.asAssume().getDynamicTypeAssumption().getDynamicLowerBoundType();
- return lattice != null && type.isDefinitelyNotNull() && lattice.isNullable()
- ? lattice.asMeetWithNotNull()
- : lattice;
+ ClassTypeElement aliasedValueType =
+ aliasedValue
+ .getDefinition()
+ .asAssume()
+ .getDynamicTypeAssumption()
+ .getDynamicLowerBoundType();
+ if (aliasedValueType != null) {
+ aliasedValueType = aliasedValueType.meetNullability(getType().nullability());
+ assert aliasedValueType.nullability().lessThanOrEqual(maxNullability);
+ return aliasedValueType;
+ }
}
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
index 3129b82..2a30a23 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -13,7 +13,9 @@
import com.android.tools.r8.ir.desugar.CfClassDesugaringEventConsumer.D8CfClassDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer;
import com.android.tools.r8.utils.ThreadUtils;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;
@@ -53,6 +55,17 @@
throws ExecutionException {
List<DexProgramClass> classes = appView.appInfo().classes();
+ if (appView.options().isDesugaredLibraryCompilation()) {
+ CfL8ClassSynthesizerEventConsumer l8ClassSynthesizerEventConsumer =
+ new CfL8ClassSynthesizerEventConsumer();
+ converter.l8ClassSynthesis(executorService, l8ClassSynthesizerEventConsumer);
+ classes =
+ ImmutableList.<DexProgramClass>builder()
+ .addAll(classes)
+ .addAll(l8ClassSynthesizerEventConsumer.getSynthesizedClasses())
+ .build();
+ }
+
D8CfClassDesugaringEventConsumer classDesugaringEventConsumer =
CfClassDesugaringEventConsumer.createForD8(methodProcessor);
converter.desugarClassesForD8(classes, classDesugaringEventConsumer, executorService);
@@ -76,11 +89,6 @@
D8CfInstructionDesugaringEventConsumer instructionDesugaringEventConsumer =
CfInstructionDesugaringEventConsumer.createForD8(methodProcessor);
- // TODO(b/191656218): Move upfront the loop and use maybe the class event consumer.
- if (appView.options().isDesugaredLibraryCompilation()) {
- converter.ensureWrappersForL8(instructionDesugaringEventConsumer);
- }
-
// Process the wave and wait for all IR processing to complete.
methodProcessor.newWave();
ThreadUtils.processItems(
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 73ef0f1..8595ecd 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
@@ -49,6 +49,8 @@
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerCollection;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer;
@@ -355,13 +357,6 @@
D8NestBasedAccessDesugaring::clearNestAttributes);
}
- public void ensureWrappersForL8(
- D8CfInstructionDesugaringEventConsumer instructionDesugaringEventConsumer) {
- assert appView.options().isDesugaredLibraryCompilation();
- instructionDesugaring.withDesugaredLibraryAPIConverter(
- converter -> converter.ensureWrappersForL8(instructionDesugaringEventConsumer));
- }
-
private void staticizeClasses(
OptimizationFeedback feedback, ExecutorService executorService, GraphLens applied)
throws ExecutionException {
@@ -414,11 +409,11 @@
reportNestDesugarDependencies();
clearNestAttributes();
- application = commitPendingSyntheticItems(appView, application);
+ application = commitPendingSyntheticItemsD8(appView, application);
postProcessingDesugaringForD8(methodProcessor, executor);
- application = commitPendingSyntheticItems(appView, application);
+ application = commitPendingSyntheticItemsD8(appView, application);
// Build a new application with jumbo string info,
Builder<?> builder = application.builder().setHighestSortingString(highestSortingString);
@@ -437,7 +432,7 @@
appView.appInfo().getMainDexInfo()));
}
- private DexApplication commitPendingSyntheticItems(
+ private DexApplication commitPendingSyntheticItemsD8(
AppView<AppInfo> appView, DexApplication application) {
if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
appView.setAppInfo(
@@ -449,6 +444,23 @@
return application;
}
+ private static void commitPendingSyntheticItemsR8(AppView<AppInfoWithLiveness> appView) {
+ if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
+ appView.setAppInfo(
+ appView
+ .appInfo()
+ .rebuildWithLiveness(appView.getSyntheticItems().commit(appView.appInfo().app())));
+ }
+ }
+
+ public void l8ClassSynthesis(
+ ExecutorService executorService,
+ CfL8ClassSynthesizerEventConsumer l8ClassSynthesizerEventConsumer)
+ throws ExecutionException {
+ new CfL8ClassSynthesizerCollection(appView, instructionDesugaring.getRetargetingInfo())
+ .synthesizeClasses(executorService, l8ClassSynthesizerEventConsumer);
+ }
+
private void postProcessingDesugaringForD8(
D8MethodProcessor methodProcessor, ExecutorService executorService)
throws ExecutionException {
@@ -726,6 +738,9 @@
// lenses with code rewriting are added.
appView.clearCodeRewritings();
+ // Commit synthetics from the primary optimization pass.
+ commitPendingSyntheticItemsR8(appView);
+
// Analyze the data collected by the argument propagator, use the analysis result to update
// the parameter optimization infos, and rewrite the application.
appView.withArgumentPropagator(
@@ -797,12 +812,8 @@
// Commit synthetics before creating a builder (otherwise the builder will not include the
// synthetics.)
- if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
- appView.setAppInfo(
- appView
- .appInfo()
- .rebuildWithLiveness(appView.getSyntheticItems().commit(appView.appInfo().app())));
- }
+ commitPendingSyntheticItemsR8(appView);
+
// Build a new application with jumbo string info.
Builder<?> builder = appView.appInfo().app().builder();
builder.setHighestSortingString(highestSortingString);
@@ -1538,7 +1549,7 @@
printMethod(code, "IR after idempotent function call canonicalization (SSA)", previous);
// Insert code to log arguments if requested.
- if (options.methodMatchesLogArgumentsFilter(method)) {
+ if (options.methodMatchesLogArgumentsFilter(method) && !method.isProcessed()) {
codeRewriter.logArgumentTypes(method, code);
assert code.isConsistentSSA();
}
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 0b29d90..6eda99c 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
@@ -6,7 +6,6 @@
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.DexClasspathClass;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
@@ -15,8 +14,8 @@
import com.android.tools.r8.ir.conversion.ClassConverterResult;
import com.android.tools.r8.ir.conversion.D8MethodProcessor;
import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPIConverterEventConsumer;
import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialBridgeInfo;
import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodDesugaringEventConsumer;
@@ -70,11 +69,6 @@
return new CfInstructionDesugaringEventConsumer() {
@Override
- public void acceptWrapperProgramClass(DexProgramClass clazz) {
- assert false;
- }
-
- @Override
public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
assert false;
}
@@ -85,21 +79,11 @@
}
@Override
- public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
- assert false;
- }
-
- @Override
public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) {
assert false;
}
@Override
- public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) {
- assert false;
- }
-
- @Override
public void acceptThrowMethod(ProgramMethod method, ProgramMethod context) {
assert false;
}
@@ -154,6 +138,11 @@
public void acceptTwrCloseResourceMethod(ProgramMethod closeMethod, ProgramMethod context) {
assert false;
}
+
+ @Override
+ public void acceptCompanionClassClinit(ProgramMethod method) {
+ assert false;
+ }
};
}
@@ -171,21 +160,11 @@
}
@Override
- public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
- methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods());
- }
-
- @Override
public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) {
// Intentionally empty.
}
@Override
- public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) {
- // Intentionally empty.
- }
-
- @Override
public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) {
methodProcessor.scheduleMethodForProcessing(backportedMethod, this);
}
@@ -247,11 +226,6 @@
}
@Override
- public void acceptWrapperProgramClass(DexProgramClass clazz) {
- methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods());
- }
-
- @Override
public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
// Intentionally empty.
}
@@ -261,6 +235,11 @@
methodProcessor.scheduleDesugaredMethodForProcessing(method);
}
+ @Override
+ public void acceptCompanionClassClinit(ProgramMethod method) {
+ methodProcessor.scheduleDesugaredMethodForProcessing(method);
+ }
+
public List<ProgramMethod> finalizeDesugaring(
AppView<?> appView, ClassConverterResult.Builder classConverterResultBuilder) {
List<ProgramMethod> needsProcessing = new ArrayList<>();
@@ -342,22 +321,16 @@
}
@Override
- public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
- // Called only in Desugared library compilation which is D8.
- assert false;
- }
-
- @Override
- public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) {
- additions.injectInterface(clazz, newInterface);
- }
-
- @Override
public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) {
additions.addLiveClasspathClass(clazz);
}
@Override
+ public void acceptCompanionClassClinit(ProgramMethod method) {
+ // TODO(b/183998768): Update this once desugaring is moved to the enqueuer.
+ }
+
+ @Override
public void acceptRecordClass(DexProgramClass recordClass) {
// This is called each time an instruction or a class is found to require the record class.
assert false : "TODO(b/179146128): To be implemented";
@@ -380,12 +353,6 @@
}
@Override
- public void acceptWrapperProgramClass(DexProgramClass clazz) {
- // Called only in Desugared library compilation which is D8.
- assert false;
- }
-
- @Override
public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
additions.addLiveClasspathClass(clazz);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizer.java
new file mode 100644
index 0000000..2eefa63
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizer.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, 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;
+
+public interface CfL8ClassSynthesizer {
+
+ void synthesizeClasses(CfL8ClassSynthesizerEventConsumer eventConsumer);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerCollection.java
new file mode 100644
index 0000000..9accf26
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerCollection.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterL8Synthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizer;
+import com.android.tools.r8.utils.ThreadUtils;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public class CfL8ClassSynthesizerCollection {
+
+ private Collection<CfL8ClassSynthesizer> synthesizers = new ArrayList<>();
+
+ public CfL8ClassSynthesizerCollection(AppView<?> appView, RetargetingInfo retargetingInfo) {
+ assert appView.options().isDesugaredLibraryCompilation();
+ EmulatedInterfaceSynthesizer emulatedInterfaceSynthesizer =
+ EmulatedInterfaceSynthesizer.create(appView);
+ if (emulatedInterfaceSynthesizer != null) {
+ synthesizers.add(emulatedInterfaceSynthesizer);
+ }
+ DesugaredLibraryRetargeterL8Synthesizer retargeterL8Synthesizer =
+ DesugaredLibraryRetargeterL8Synthesizer.create(appView, retargetingInfo);
+ if (retargeterL8Synthesizer != null) {
+ synthesizers.add(retargeterL8Synthesizer);
+ }
+ synthesizers.add(new DesugaredLibraryWrapperSynthesizer(appView));
+ }
+
+ public void synthesizeClasses(
+ ExecutorService executorService, CfL8ClassSynthesizerEventConsumer eventConsumer)
+ throws ExecutionException {
+ ThreadUtils.processItems(
+ synthesizers, synthesizer -> synthesizer.synthesizeClasses(eventConsumer), executorService);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerEventConsumer.java
new file mode 100644
index 0000000..5e41810
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerEventConsumer.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer;
+import com.google.common.collect.Sets;
+import java.util.Set;
+
+public class CfL8ClassSynthesizerEventConsumer
+ implements EmulatedInterfaceSynthesizerEventConsumer,
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer,
+ DesugaredLibraryRetargeterL8SynthesizerEventConsumer {
+
+ private Set<DexProgramClass> synthesizedClasses = Sets.newConcurrentHashSet();
+
+ @Override
+ public void acceptEmulatedInterface(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
+
+ @Override
+ public void acceptWrapperProgramClass(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
+
+ @Override
+ public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
+
+ public Set<DexProgramClass> getSynthesizedClasses() {
+ return synthesizedClasses;
+ }
+
+}
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 e539861..2d99720 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
@@ -53,7 +53,8 @@
InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
RetargetingInfo retargetingInfo) {
ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
- if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
+ if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
+ && !appView.options().isDesugaredLibraryCompilation()) {
desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
}
if (interfaceMethodProcessorFacade != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
index d0b798b..95407f8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
@@ -8,8 +8,8 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.D8MethodProcessor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer.DesugaredLibraryAPIConverterPostProcessingEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
import com.android.tools.r8.ir.desugar.itf.InterfaceProcessingDesugaringEventConsumer;
import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -23,7 +23,7 @@
public abstract class CfPostProcessingDesugaringEventConsumer
implements DesugaredLibraryRetargeterPostProcessingEventConsumer,
InterfaceProcessingDesugaringEventConsumer,
- DesugaredLibraryAPIConverterPostProcessingEventConsumer {
+ DesugaredLibraryAPICallbackSynthesizorEventConsumer {
public static D8CfPostProcessingDesugaringEventConsumer createForD8(
D8MethodProcessor methodProcessor) {
@@ -38,6 +38,7 @@
public static class D8CfPostProcessingDesugaringEventConsumer
extends CfPostProcessingDesugaringEventConsumer {
+
private final D8MethodProcessor methodProcessor;
// Methods cannot be processed directly because we cannot add method to classes while
// concurrently processing other methods.
@@ -48,11 +49,6 @@
}
@Override
- public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
- methodsToReprocess.addAll(clazz.programMethods());
- }
-
- @Override
public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) {
// Intentionally empty.
}
@@ -73,11 +69,6 @@
}
@Override
- public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
- methodsToReprocess.add(method);
- }
-
- @Override
public void finalizeDesugaring() throws ExecutionException {
assert methodProcessor.verifyNoPendingMethodProcessing();
methodProcessor.newWave();
@@ -89,10 +80,16 @@
public void acceptAPIConversionCallback(ProgramMethod method) {
methodsToReprocess.add(method);
}
+
+ @Override
+ public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
+ // Intentionally empty.
+ }
}
public static class R8PostProcessingDesugaringEventConsumer
extends CfPostProcessingDesugaringEventConsumer {
+
private final SyntheticAdditions additions;
R8PostProcessingDesugaringEventConsumer(SyntheticAdditions additions) {
@@ -105,11 +102,6 @@
}
@Override
- public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
- additions.addLiveMethods(clazz.programMethods());
- }
-
- @Override
public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) {
additions.injectInterface(clazz, newInterface);
}
@@ -130,13 +122,13 @@
}
@Override
- public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
- assert false : "TODO(b/183998768): Support Interface processing in R8";
+ public void acceptAPIConversionCallback(ProgramMethod method) {
+ additions.addLiveMethod(method);
}
@Override
- public void acceptAPIConversionCallback(ProgramMethod method) {
- additions.addLiveMethod(method);
+ public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
+ additions.addLiveClasspathClass(clazz);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 88f451b..61e6828 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.ir.desugar;
import static com.android.tools.r8.ir.desugar.lambda.ForcefullyMovedLambdaMethodConsumer.emptyForcefullyMovedLambdaMethodConsumer;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
import com.android.tools.r8.dex.Constants;
@@ -40,11 +39,11 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
-import java.util.function.Function;
/**
* Represents lambda class generated for a lambda descriptor in context of lambda instantiation
@@ -109,7 +108,7 @@
this.lambdaField =
!stateless ? null : factory.createField(type, type, factory.lambdaInstanceFieldName);
- // Synthesize the program class one all fields are set.
+ // Synthesize the program class once all fields are set.
synthesizeLambdaClass(builder);
}
@@ -244,7 +243,8 @@
null,
deprecated,
d8R8Synthesized,
- getApiLevelIfEnabledForNewMember(appView, Function.identity())));
+ // The api level is computed when tracing.
+ AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView)));
}
builder.setInstanceFields(fields);
}
@@ -270,7 +270,8 @@
DexValueNull.NULL,
deprecated,
d8R8Synthesized,
- getApiLevelIfEnabledForNewMember(appView, Function.identity()))));
+ // The api level is computed when tracing.
+ AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView))));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java
index cfcb9b0..3e0143a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java
@@ -19,8 +19,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer.DesugaredLibraryAPIConverterPostProcessingEventConsumer;
-import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperCfCodeProvider;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
+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;
@@ -190,17 +190,16 @@
private ProgramMethod generateCallbackMethod(
DexEncodedMethod originalMethod,
DexProgramClass clazz,
- DesugaredLibraryAPIConverterPostProcessingEventConsumer eventConsumer) {
+ DesugaredLibraryAPICallbackSynthesizorEventConsumer eventConsumer) {
DexMethod methodToInstall =
methodWithVivifiedTypeInSignature(originalMethod.getReference(), clazz.type, appView);
CfCode cfCode =
- new APIConverterWrapperCfCodeProvider(
+ new APICallbackWrapperCfCodeProvider(
appView,
originalMethod.getReference(),
- null,
wrapperSynthesizor,
clazz.isInterface(),
- null)
+ eventConsumer)
.generateCfCode();
DexEncodedMethod newMethod =
wrapperSynthesizor.newSynthesizedMethod(methodToInstall, originalMethod, cfCode);
@@ -209,11 +208,8 @@
newMethod.setLibraryMethodOverride(OptionalBool.TRUE);
}
ProgramMethod callback = new ProgramMethod(clazz, newMethod);
- if (eventConsumer != null) {
- eventConsumer.acceptAPIConversionCallback(callback);
- } else {
- assert appView.enableWholeProgramOptimizations();
- }
+ assert eventConsumer != null;
+ eventConsumer.acceptAPIConversionCallback(callback);
return callback;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
index ebab39e..be8ac84 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
@@ -34,6 +34,7 @@
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConversionCfCodeProvider;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -241,12 +242,6 @@
DexProto newProto = appView.dexItemFactory().createProto(newReturnType, newParameters);
return appView.dexItemFactory().createMethod(holder, newProto, originalMethod.name);
}
-
- public void ensureWrappersForL8(CfInstructionDesugaringEventConsumer eventConsumer) {
- assert appView.options().isDesugaredLibraryCompilation();
- wrapperSynthesizor.ensureWrappersForL8(eventConsumer);
- }
-
public void generateTrackingWarnings() {
generateTrackDesugaredAPIWarnings(trackedAPIs, "", appView);
}
@@ -324,7 +319,8 @@
}
private DexMethod computeReturnConversion(
- DexMethod invokedMethod, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+ DexMethod invokedMethod,
+ DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) {
DexType returnType = invokedMethod.proto.returnType;
if (wrapperSynthesizor.shouldConvert(returnType, invokedMethod)) {
DexType newReturnType = DesugaredLibraryAPIConverter.vivifiedTypeFor(returnType, appView);
@@ -335,7 +331,8 @@
}
private DexMethod[] computeParameterConversions(
- DexMethod invokedMethod, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+ DexMethod invokedMethod,
+ DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) {
DexMethod[] parameterConversions = new DexMethod[invokedMethod.getArity()];
DexType[] parameters = invokedMethod.proto.parameters.values;
for (int i = 0; i < parameters.length; i++) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java
deleted file mode 100644
index 7af64bb..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2021, 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;
-
-import com.android.tools.r8.graph.DexClasspathClass;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramMethod;
-
-public interface DesugaredLibraryAPIConverterEventConsumer {
-
- void acceptWrapperProgramClass(DexProgramClass clazz);
-
- void acceptWrapperClasspathClass(DexClasspathClass clazz);
-
- void acceptAPIConversion(ProgramMethod method);
-
- interface DesugaredLibraryAPIConverterPostProcessingEventConsumer {
-
- void acceptAPIConversionCallback(ProgramMethod method);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
index a4c9b12..8a59f14 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
import java.util.Collection;
import java.util.Collections;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterInstructionEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterInstructionEventConsumer.java
deleted file mode 100644
index ae7630d..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterInstructionEventConsumer.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2021, 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;
-
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClasspathClass;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramMethod;
-
-public interface DesugaredLibraryRetargeterInstructionEventConsumer {
-
- void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz);
-
- void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz);
-
- void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface);
-
- interface DesugaredLibraryRetargeterPostProcessingEventConsumer
- extends DesugaredLibraryRetargeterInstructionEventConsumer {
-
- void acceptForwardingMethod(ProgramMethod method);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java
new file mode 100644
index 0000000..dad4cd6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizer;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer;
+import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
+
+public class DesugaredLibraryRetargeterL8Synthesizer implements CfL8ClassSynthesizer {
+
+ private final AppView<?> appView;
+ private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
+ private final DexClassAndMethodSet emulatedDispatchMethods;
+
+ public static DesugaredLibraryRetargeterL8Synthesizer create(
+ AppView<?> appView, RetargetingInfo retargetingInfo) {
+ assert appView.options().isDesugaredLibraryCompilation();
+ if (retargetingInfo == null || retargetingInfo.getEmulatedDispatchMethods().isEmpty()) {
+ assert appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty();
+ return null;
+ }
+ return new DesugaredLibraryRetargeterL8Synthesizer(appView, retargetingInfo);
+ }
+
+ public DesugaredLibraryRetargeterL8Synthesizer(
+ AppView<?> appView, RetargetingInfo retargetingInfo) {
+ this.appView = appView;
+ this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
+ emulatedDispatchMethods = retargetingInfo.getEmulatedDispatchMethods();
+ }
+
+ @Override
+ public void synthesizeClasses(CfL8ClassSynthesizerEventConsumer eventConsumer) {
+ assert !emulatedDispatchMethods.isEmpty();
+ for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) {
+ syntheticHelper.ensureProgramEmulatedHolderDispatchMethod(
+ emulatedDispatchMethod, eventConsumer);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
index 64d3cc6..b6200cb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
import com.google.common.collect.Maps;
@@ -49,11 +49,8 @@
CfPostProcessingDesugaringEventConsumer eventConsumer,
ExecutorService executorService)
throws ExecutionException {
- if (appView.options().isDesugaredLibraryCompilation()) {
- ensureEmulatedDispatchMethodsSynthesized(eventConsumer);
- } else {
- ensureInterfacesAndForwardingMethodsSynthesized(programClasses, eventConsumer);
- }
+ assert !appView.options().isDesugaredLibraryCompilation();
+ ensureInterfacesAndForwardingMethodsSynthesized(programClasses, eventConsumer);
}
private void ensureInterfacesAndForwardingMethodsSynthesized(
@@ -150,17 +147,6 @@
return desugaringForwardingMethod;
}
- private void ensureEmulatedDispatchMethodsSynthesized(
- DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
- assert appView.options().isDesugaredLibraryCompilation();
- if (emulatedDispatchMethods.isEmpty()) {
- return;
- }
- for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) {
- syntheticHelper.ensureEmulatedHolderDispatchMethod(emulatedDispatchMethod, eventConsumer);
- }
- }
-
private void reportInvalidLibrarySupertype(
DexLibraryClass libraryClass, DexClassAndMethodSet retarget) {
DexClass dexClass = appView.definitionFor(libraryClass.superType);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
new file mode 100644
index 0000000..fab6f10
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClasspathClass;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface DesugaredLibraryRetargeterSynthesizerEventConsumer {
+
+ interface DesugaredLibraryRetargeterL8SynthesizerEventConsumer {
+ void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz);
+ }
+
+ interface DesugaredLibraryRetargeterInstructionEventConsumer {
+ void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz);
+ }
+
+ interface DesugaredLibraryRetargeterPostProcessingEventConsumer
+ extends DesugaredLibraryRetargeterInstructionEventConsumer {
+ void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface);
+
+ void acceptForwardingMethod(ProgramMethod method);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
index 02eb59b..9569c61 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -11,6 +11,8 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
import com.android.tools.r8.synthesis.SyntheticClassBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -28,91 +30,99 @@
public DexClass ensureEmulatedHolderDispatchMethod(
DexClassAndMethod emulatedDispatchMethod,
DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
- assert eventConsumer != null || appView.enableWholeProgramOptimizations();
+ assert eventConsumer != null;
+ if (appView.options().isDesugaredLibraryCompilation()) {
+ return appView
+ .getSyntheticItems()
+ .getExistingFixedClass(
+ SyntheticKind.RETARGET_CLASS, emulatedDispatchMethod.getHolder(), appView);
+ }
DexClass interfaceClass =
ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer);
DexMethod itfMethod =
interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference();
- DexClass holderDispatch;
- if (appView.options().isDesugaredLibraryCompilation()) {
- holderDispatch =
- appView
- .getSyntheticItems()
- .ensureFixedClass(
- SyntheticKind.RETARGET_CLASS,
- emulatedDispatchMethod.getHolder(),
- appView,
- classBuilder ->
- buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
- clazz -> {
- if (eventConsumer != null) {
- eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
- }
- });
- } else {
- ClasspathOrLibraryClass context =
- emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
- assert context != null;
- holderDispatch =
- appView
- .getSyntheticItems()
- .ensureFixedClasspathClass(
- SyntheticKind.RETARGET_CLASS,
- context,
- appView,
- classBuilder ->
- buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
- clazz -> {
- if (eventConsumer != null) {
- eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
- }
- });
- }
- rewriteType(holderDispatch.type);
- return holderDispatch;
+ ClasspathOrLibraryClass context =
+ emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
+ assert context != null;
+ return appView
+ .getSyntheticItems()
+ .ensureFixedClasspathClass(
+ SyntheticKind.RETARGET_CLASS,
+ context,
+ appView,
+ classBuilder ->
+ buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
+ clazz -> {
+ eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
+ rewriteType(clazz.type);
+ });
+ }
+
+ public void ensureProgramEmulatedHolderDispatchMethod(
+ DexClassAndMethod emulatedDispatchMethod,
+ DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) {
+ assert eventConsumer != null;
+ assert appView.options().isDesugaredLibraryCompilation();
+ DexClass interfaceClass =
+ ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer);
+ DexMethod itfMethod =
+ interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference();
+ appView
+ .getSyntheticItems()
+ .ensureFixedClass(
+ SyntheticKind.RETARGET_CLASS,
+ emulatedDispatchMethod.getHolder(),
+ appView,
+ classBuilder ->
+ buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
+ clazz -> {
+ eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
+ rewriteType(clazz.type);
+ });
}
public DexClass ensureEmulatedInterfaceDispatchMethod(
DexClassAndMethod emulatedDispatchMethod,
DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
- assert eventConsumer != null || appView.enableWholeProgramOptimizations();
- DexClass interfaceDispatch;
+ assert eventConsumer != null;
if (appView.options().isDesugaredLibraryCompilation()) {
- interfaceDispatch =
- appView
- .getSyntheticItems()
- .ensureFixedClass(
- SyntheticKind.RETARGET_INTERFACE,
- emulatedDispatchMethod.getHolder(),
- appView,
- classBuilder ->
- buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
- clazz -> {
- if (eventConsumer != null) {
- eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
- }
- });
- } else {
- ClasspathOrLibraryClass context =
- emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
- assert context != null;
- interfaceDispatch =
- appView
- .getSyntheticItems()
- .ensureFixedClasspathClass(
- SyntheticKind.RETARGET_INTERFACE,
- context,
- appView,
- classBuilder ->
- buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
- clazz -> {
- if (eventConsumer != null) {
- eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
- }
- });
+ return appView
+ .getSyntheticItems()
+ .getExistingFixedClass(
+ SyntheticKind.RETARGET_INTERFACE, emulatedDispatchMethod.getHolder(), appView);
}
- rewriteType(interfaceDispatch.type);
- return interfaceDispatch;
+ ClasspathOrLibraryClass context =
+ emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
+ assert context != null;
+ return appView
+ .getSyntheticItems()
+ .ensureFixedClasspathClass(
+ SyntheticKind.RETARGET_INTERFACE,
+ context,
+ appView,
+ classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
+ clazz -> {
+ eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
+ rewriteType(clazz.type);
+ });
+ }
+
+ public DexClass ensureEmulatedInterfaceDispatchMethod(
+ DexClassAndMethod emulatedDispatchMethod,
+ DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) {
+ assert appView.options().isDesugaredLibraryCompilation();
+ assert eventConsumer != null;
+ return appView
+ .getSyntheticItems()
+ .ensureFixedClass(
+ SyntheticKind.RETARGET_INTERFACE,
+ emulatedDispatchMethod.getHolder(),
+ appView,
+ classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
+ clazz -> {
+ eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
+ rewriteType(clazz.type);
+ });
}
private void buildInterfaceDispatchMethod(
@@ -149,14 +159,16 @@
.setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
.setCode(
methodSig ->
- new EmulateInterfaceSyntheticCfCodeProvider(
- methodSig.getHolderType(),
- emulatedDispatchMethod.getHolderType(),
- desugarMethod,
- itfMethod,
- Collections.emptyList(),
- appView)
- .generateCfCode());
+ appView.options().isDesugaredLibraryCompilation()
+ ? new EmulateInterfaceSyntheticCfCodeProvider(
+ methodSig.getHolderType(),
+ emulatedDispatchMethod.getHolderType(),
+ desugarMethod,
+ itfMethod,
+ Collections.emptyList(),
+ appView)
+ .generateCfCode()
+ : null);
});
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
index 2605672..3e21feb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexClasspathClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -19,13 +18,17 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
-import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizer;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterConstructorCfCodeProvider;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterThrowRuntimeExceptionCfCodeProvider;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterVivifiedWrapperCfCodeProvider;
@@ -39,12 +42,12 @@
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
import java.util.function.Function;
// I am responsible for the generation of wrappers used to call library APIs when desugaring
@@ -90,14 +93,14 @@
// return new j$....BiFunction$-WRP(wrappedValue);
// }
// }
-public class DesugaredLibraryWrapperSynthesizer {
+public class DesugaredLibraryWrapperSynthesizer implements CfL8ClassSynthesizer {
private final AppView<?> appView;
private final DexItemFactory factory;
private final ConcurrentHashMap<DexType, List<DexEncodedMethod>> allImplementedMethodsCache =
new ConcurrentHashMap<>();
- DesugaredLibraryWrapperSynthesizer(AppView<?> appView) {
+ public DesugaredLibraryWrapperSynthesizer(AppView<?> appView) {
this.appView = appView;
this.factory = appView.dexItemFactory();
}
@@ -122,20 +125,49 @@
DexType type,
DexType srcType,
DexType destType,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+ DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) {
+ DexMethod customConversion = getCustomConversion(type, srcType, destType);
+ if (customConversion != null) {
+ return customConversion;
+ }
+ assert canGenerateWrapper(type) : type;
+ DexClass clazz = getValidClassToWrap(type);
+ WrapperConversions wrapperConversions = ensureWrappers(clazz, eventConsumer);
+ DexMethod conversion =
+ type == srcType
+ ? wrapperConversions.getConversion()
+ : wrapperConversions.getVivifiedConversion();
+ assert srcType == conversion.getArgumentType(0, true);
+ assert destType == conversion.getReturnType();
+ return conversion;
+ }
+
+ public DexMethod getExistingProgramConversionMethod(
+ DexType type, DexType srcType, DexType destType) {
+ DexMethod customConversion = getCustomConversion(type, srcType, destType);
+ if (customConversion != null) {
+ return customConversion;
+ }
+ WrapperConversions wrapperConversions =
+ getExistingProgramWrapperConversions(getValidClassToWrap(type));
+ DexMethod conversion =
+ type == srcType
+ ? wrapperConversions.getConversion()
+ : wrapperConversions.getVivifiedConversion();
+ assert srcType == conversion.getArgumentType(0, true);
+ return conversion;
+ }
+
+ 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().desugaredLibraryConfiguration.getCustomConversions().get(type);
- if (conversionHolder == null) {
- conversionHolder =
- type == srcType
- ? ensureTypeWrapper(type, eventConsumer)
- : ensureVivifiedTypeWrapper(type, eventConsumer);
+ if (conversionHolder != null) {
+ return factory.createMethod(
+ conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName);
}
- assert conversionHolder != null;
- return factory.createMethod(
- conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName);
+ return null;
}
private boolean canConvert(DexType type) {
@@ -165,16 +197,6 @@
return appView.options().desugaredLibraryConfiguration.getWrapperConversions().contains(type);
}
- private DexType ensureTypeWrapper(
- DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
- return ensureWrappers(type, eventConsumer).getWrapper().type;
- }
-
- private DexType ensureVivifiedTypeWrapper(
- DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
- return ensureWrappers(type, eventConsumer).getVivifiedWrapper().type;
- }
-
private DexClass getValidClassToWrap(DexType type) {
DexClass dexClass = appView.definitionFor(type);
// The dexClass should be a library class, so it cannot be null.
@@ -188,102 +210,78 @@
return DesugaredLibraryAPIConverter.vivifiedTypeFor(type, appView);
}
- static class Wrappers {
- private final DexClass wrapper;
- private final DexClass vivifiedWrapper;
+ static class WrapperConversions {
- Wrappers(DexClass wrapper, DexClass vivifiedWrapper) {
- this.wrapper = wrapper;
- this.vivifiedWrapper = vivifiedWrapper;
+ private final DexMethod conversion;
+ private final DexMethod vivifiedConversion;
+
+ WrapperConversions(DexMethod conversion, DexMethod vivifiedConversion) {
+ this.conversion = conversion;
+ this.vivifiedConversion = vivifiedConversion;
}
- public DexClass getWrapper() {
- return wrapper;
+ public DexMethod getConversion() {
+ return conversion;
}
- public DexClass getVivifiedWrapper() {
- return vivifiedWrapper;
+ public DexMethod getVivifiedConversion() {
+ return vivifiedConversion;
}
}
- private Wrappers ensureWrappers(
- DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
- assert canGenerateWrapper(type) : type;
- DexClass dexClass = getValidClassToWrap(type);
- return ensureWrappers(dexClass, ignored -> {}, eventConsumer);
- }
-
- private Wrappers ensureWrappers(
- DexClass context,
- Consumer<DexClasspathClass> creationCallback,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
- DexType type = context.type;
- DexClass wrapper;
- DexClass vivifiedWrapper;
+ private WrapperConversions ensureWrappers(
+ DexClass context, DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) {
+ assert eventConsumer != null;
if (context.isProgramClass()) {
- assert appView.options().isDesugaredLibraryCompilation();
- DexProgramClass programContext = context.asProgramClass();
- wrapper =
- ensureProgramWrapper(
- SyntheticKind.WRAPPER,
- vivifiedTypeFor(type),
- type,
- programContext,
- eventConsumer,
- wrapperField ->
- synthesizeVirtualMethodsForTypeWrapper(
- programContext, wrapperField, eventConsumer));
- vivifiedWrapper =
- ensureProgramWrapper(
- SyntheticKind.VIVIFIED_WRAPPER,
- type,
- vivifiedTypeFor(type),
- programContext,
- eventConsumer,
- wrapperField ->
- synthesizeVirtualMethodsForVivifiedTypeWrapper(
- programContext, wrapperField, eventConsumer));
- DexField wrapperField = getWrapperUniqueField(wrapper);
- DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper);
- ensureProgramConversionMethod(
- SyntheticKind.WRAPPER, programContext, wrapperField, vivifiedWrapperField);
- ensureProgramConversionMethod(
- SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapperField, wrapperField);
- } else {
- assert context.isNotProgramClass();
- ClasspathOrLibraryClass classpathOrLibraryContext = context.asClasspathOrLibraryClass();
- wrapper =
- ensureClasspathWrapper(
- SyntheticKind.WRAPPER,
- vivifiedTypeFor(type),
- type,
- classpathOrLibraryContext,
- creationCallback,
- eventConsumer,
- wrapperField ->
- synthesizeVirtualMethodsForTypeWrapper(context, wrapperField, eventConsumer));
- vivifiedWrapper =
- ensureClasspathWrapper(
- SyntheticKind.VIVIFIED_WRAPPER,
- type,
- vivifiedTypeFor(type),
- classpathOrLibraryContext,
- creationCallback,
- eventConsumer,
- wrapperField ->
- synthesizeVirtualMethodsForVivifiedTypeWrapper(
- context, wrapperField, eventConsumer));
- DexField wrapperField = getWrapperUniqueField(wrapper);
- DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper);
- ensureClasspathConversionMethod(
- SyntheticKind.WRAPPER, classpathOrLibraryContext, wrapperField, vivifiedWrapperField);
- ensureClasspathConversionMethod(
- SyntheticKind.VIVIFIED_WRAPPER,
- classpathOrLibraryContext,
- vivifiedWrapperField,
- wrapperField);
+ return getExistingProgramWrapperConversions(context);
}
- return new Wrappers(wrapper, vivifiedWrapper);
+ assert context.isNotProgramClass();
+ ClasspathOrLibraryClass classpathOrLibraryContext = context.asClasspathOrLibraryClass();
+ DexType type = context.type;
+ DexType vivifiedType = vivifiedTypeFor(type);
+ DexClass wrapper =
+ ensureClasspathWrapper(
+ SyntheticKind.WRAPPER,
+ vivifiedType,
+ type,
+ classpathOrLibraryContext,
+ eventConsumer,
+ wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, wrapperField));
+ DexClass vivifiedWrapper =
+ ensureClasspathWrapper(
+ SyntheticKind.VIVIFIED_WRAPPER,
+ type,
+ vivifiedType,
+ classpathOrLibraryContext,
+ eventConsumer,
+ wrapperField -> synthesizeVirtualMethodsForVivifiedTypeWrapper(context, wrapperField));
+ return new WrapperConversions(
+ getConversion(wrapper, vivifiedType, type),
+ getConversion(vivifiedWrapper, type, vivifiedType));
+ }
+
+ private WrapperConversions getExistingProgramWrapperConversions(DexClass context) {
+ DexClass vivifiedWrapper;
+ DexClass wrapper;
+ assert appView.options().isDesugaredLibraryCompilation();
+ wrapper = getExistingProgramWrapper(context, SyntheticKind.WRAPPER);
+ vivifiedWrapper = getExistingProgramWrapper(context, SyntheticKind.VIVIFIED_WRAPPER);
+ DexField wrapperField = getWrapperUniqueField(wrapper);
+ DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper);
+ return new WrapperConversions(
+ getConversion(wrapper, vivifiedWrapperField.type, wrapperField.type),
+ getConversion(vivifiedWrapper, wrapperField.type, vivifiedWrapperField.type));
+ }
+
+ private DexProgramClass getExistingProgramWrapper(DexClass context, SyntheticKind kind) {
+ return appView.getSyntheticItems().getExistingFixedClass(kind, context, appView);
+ }
+
+ private DexMethod getConversion(DexClass wrapper, DexType returnType, DexType argType) {
+ DexMethod convertMethod =
+ factory.createMethod(
+ wrapper.type, factory.createProto(returnType, argType), factory.convertMethodName);
+ return wrapper.lookupDirectMethod(convertMethod).getReference();
}
private DexEncodedField getWrapperUniqueEncodedField(DexClass wrapper) {
@@ -300,8 +298,9 @@
DexType wrappingType,
DexType wrappedType,
DexProgramClass programContext,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer,
- Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) {
+ DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer) {
+ assert appView.options().isDesugaredLibraryCompilation();
+ assert eventConsumer != null;
return appView
.getSyntheticItems()
.ensureFixedClass(
@@ -311,13 +310,7 @@
builder -> buildWrapper(wrappingType, wrappedType, programContext, builder),
// The creation of virtual methods may require new wrappers, this needs to happen
// once the wrapper is created to avoid infinite recursion.
- wrapper -> {
- if (eventConsumer != null) {
- eventConsumer.acceptWrapperProgramClass(wrapper);
- }
- wrapper.setVirtualMethods(
- virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper)));
- });
+ eventConsumer::acceptWrapperProgramClass);
}
private DexClasspathClass ensureClasspathWrapper(
@@ -325,101 +318,84 @@
DexType wrappingType,
DexType wrappedType,
ClasspathOrLibraryClass classpathOrLibraryContext,
- Consumer<DexClasspathClass> creationCallback,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer,
- Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) {
+ DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
+ Function<DexEncodedField, Collection<DexEncodedMethod>> virtualMethodProvider) {
+ assert eventConsumer != null;
return appView
.getSyntheticItems()
.ensureFixedClasspathClass(
kind,
classpathOrLibraryContext,
appView,
- builder ->
- buildWrapper(
- wrappingType, wrappedType, classpathOrLibraryContext.asDexClass(), builder),
- // The creation of virtual methods may require new wrappers, this needs to happen
- // once the wrapper is created to avoid infinite recursion.
- wrapper -> {
- if (eventConsumer != null) {
- eventConsumer.acceptWrapperClasspathClass(wrapper);
- }
- wrapper.setVirtualMethods(
- virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper)));
- creationCallback.accept(wrapper);
- });
+ builder -> {
+ DexEncodedField wrapperField =
+ buildWrapper(
+ wrappingType, wrappedType, classpathOrLibraryContext.asDexClass(), builder);
+ builder.addMethod(
+ methodBuilder ->
+ buildConversionMethod(
+ methodBuilder, factory.createProto(wrappingType, wrappedType), null));
+ builder.setVirtualMethods(virtualMethodProvider.apply(wrapperField));
+ },
+ eventConsumer::acceptWrapperClasspathClass);
}
- private ProgramMethod ensureProgramConversionMethod(
- SyntheticKind kind,
- DexProgramClass context,
- DexField wrapperField,
- DexField reverseWrapperField) {
- return appView
+ private void getExistingProgramConversionMethod(
+ SyntheticKind kind, DexProgramClass context, DexClass wrapper, DexClass reverseWrapper) {
+ DexField wrapperField = getWrapperUniqueField(wrapper);
+ DexField reverseWrapperField = getWrapperUniqueField(reverseWrapper);
+ DexProto proto = factory.createProto(reverseWrapperField.type, wrapperField.type);
+ appView
.getSyntheticItems()
.ensureFixedClassMethod(
factory.convertMethodName,
- factory.createProto(reverseWrapperField.type, wrapperField.type),
- kind,
- context,
- appView,
- ignored -> {},
- methodBuilder ->
- buildConversionMethod(methodBuilder, wrapperField, reverseWrapperField, context));
- }
-
- private DexClassAndMethod ensureClasspathConversionMethod(
- SyntheticKind kind,
- ClasspathOrLibraryClass context,
- DexField wrapperField,
- DexField reverseWrapperField) {
- return appView
- .getSyntheticItems()
- .ensureFixedClasspathClassMethod(
- factory.convertMethodName,
- factory.createProto(reverseWrapperField.type, wrapperField.type),
+ proto,
kind,
context,
appView,
ignored -> {},
methodBuilder ->
buildConversionMethod(
- methodBuilder, wrapperField, reverseWrapperField, context.asDexClass()));
+ methodBuilder,
+ proto,
+ computeProgramConversionMethodCode(
+ wrapperField, reverseWrapperField, context)));
}
private boolean isInvalidWrapper(DexClass clazz) {
return Iterables.any(allImplementedMethods(clazz), DexEncodedMethod::isFinal);
}
- private void buildConversionMethod(
- SyntheticMethodBuilder methodBuilder,
- DexField wrapperField,
- DexField reverseWrapperField,
- DexClass context) {
- CfCode cfCode;
+ private CfCode computeProgramConversionMethodCode(
+ DexField wrapperField, DexField reverseWrapperField, DexClass context) {
if (isInvalidWrapper(context)) {
- cfCode =
- new APIConverterThrowRuntimeExceptionCfCodeProvider(
- appView,
- factory.createString(
- "Unsupported conversion for "
- + context.type
- + ". See compilation time warnings for more details."),
- wrapperField.holder)
- .generateCfCode();
- } else {
- cfCode =
- new APIConverterWrapperConversionCfCodeProvider(
- appView, reverseWrapperField, wrapperField)
- .generateCfCode();
+ return new APIConverterThrowRuntimeExceptionCfCodeProvider(
+ appView,
+ factory.createString(
+ "Unsupported conversion for "
+ + context.type
+ + ". See compilation time warnings for more details."),
+ wrapperField.holder)
+ .generateCfCode();
}
+ assert context.isProgramClass();
+ return new APIConverterWrapperConversionCfCodeProvider(
+ appView, reverseWrapperField, wrapperField)
+ .generateCfCode();
+ }
+
+ private void buildConversionMethod(
+ SyntheticMethodBuilder methodBuilder, DexProto proto, CfCode cfCode) {
methodBuilder
+ .setName(factory.convertMethodName)
+ .setProto(proto)
.setAccessFlags(
MethodAccessFlags.fromCfAccessFlags(
Constants.ACC_SYNTHETIC | Constants.ACC_STATIC | Constants.ACC_PUBLIC, false))
.setCode(methodSignature -> cfCode);
}
- private void buildWrapper(
+ private DexEncodedField buildWrapper(
DexType wrappingType,
DexType wrappedType,
DexClass clazz,
@@ -435,6 +411,7 @@
.setSuperType(superType)
.setInstanceFields(Collections.singletonList(wrapperField))
.addMethod(methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder));
+ return wrapperField;
}
private void buildWrapperConstructor(
@@ -451,10 +428,8 @@
.generateCfCode());
}
- private DexEncodedMethod[] synthesizeVirtualMethodsForVivifiedTypeWrapper(
- DexClass dexClass,
- DexEncodedField wrapperField,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+ private Collection<DexEncodedMethod> synthesizeVirtualMethodsForVivifiedTypeWrapper(
+ DexClass dexClass, DexEncodedField wrapperField) {
List<DexEncodedMethod> dexMethods = allImplementedMethods(dexClass);
List<DexEncodedMethod> generatedMethods = new ArrayList<>();
// Each method should use only types in their signature, but each method the wrapper forwards
@@ -489,16 +464,13 @@
if (dexEncodedMethod.isFinal()) {
finalMethods.add(dexEncodedMethod.getReference());
continue;
- } else {
+ } else if (dexClass.isProgramClass()) {
cfCode =
new APIConverterVivifiedWrapperCfCodeProvider(
- appView,
- methodToInstall,
- wrapperField.getReference(),
- this,
- isInterface,
- eventConsumer)
+ appView, methodToInstall, wrapperField.getReference(), this, isInterface)
.generateCfCode();
+ } else {
+ cfCode = null;
}
DexEncodedMethod newDexEncodedMethod =
newSynthesizedMethod(methodToInstall, dexEncodedMethod, cfCode);
@@ -507,10 +479,8 @@
return finalizeWrapperMethods(generatedMethods, finalMethods);
}
- private DexEncodedMethod[] synthesizeVirtualMethodsForTypeWrapper(
- DexClass dexClass,
- DexEncodedField wrapperField,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+ private Collection<DexEncodedMethod> synthesizeVirtualMethodsForTypeWrapper(
+ DexClass dexClass, DexEncodedField wrapperField) {
List<DexEncodedMethod> dexMethods = allImplementedMethods(dexClass);
List<DexEncodedMethod> generatedMethods = new ArrayList<>();
// Each method should use only vivified types in their signature, but each method the wrapper
@@ -535,16 +505,17 @@
if (dexEncodedMethod.isFinal()) {
finalMethods.add(dexEncodedMethod.getReference());
continue;
- } else {
+ } else if (dexClass.isProgramClass()) {
cfCode =
new APIConverterWrapperCfCodeProvider(
appView,
dexEncodedMethod.getReference(),
wrapperField.getReference(),
this,
- isInterface,
- eventConsumer)
+ isInterface)
.generateCfCode();
+ } else {
+ cfCode = null;
}
DexEncodedMethod newDexEncodedMethod =
newSynthesizedMethod(methodToInstall, dexEncodedMethod, cfCode);
@@ -553,14 +524,14 @@
return finalizeWrapperMethods(generatedMethods, finalMethods);
}
- private DexEncodedMethod[] finalizeWrapperMethods(
+ private Collection<DexEncodedMethod> finalizeWrapperMethods(
List<DexEncodedMethod> generatedMethods, Set<DexMethod> finalMethods) {
if (finalMethods.isEmpty()) {
- return generatedMethods.toArray(DexEncodedMethod.EMPTY_ARRAY);
+ return generatedMethods;
}
// Wrapper is invalid, no need to add the virtual methods.
reportFinalMethodsInWrapper(finalMethods);
- return DexEncodedMethod.EMPTY_ARRAY;
+ return Collections.emptyList();
}
private void reportFinalMethodsInWrapper(Set<DexMethod> methods) {
@@ -582,9 +553,9 @@
DexMethod methodToInstall, DexEncodedMethod template, Code code) {
MethodAccessFlags newFlags = template.accessFlags.copy();
assert newFlags.isPublic();
- if (code == null) {
- newFlags.setAbstract();
- } else {
+ // It can happen that we wrap an abstract method, in which case the wrapping method is no
+ // longer abstract.
+ if (code != null) {
newFlags.unsetAbstract();
}
// TODO(b/146114533): Fix inlining in synthetic methods and remove unsetBridge.
@@ -657,16 +628,63 @@
field, fieldAccessFlags, FieldTypeSignature.noSignature(), DexAnnotationSet.empty(), null);
}
- void ensureWrappersForL8(DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+ // Program wrappers are harder to deal with than classpath wrapper because generating a method's
+ // code may require other wrappers. To keep it simple (This is L8 specific), we generate first
+ // the wrappers with the conversion methods only, then the virtual methods assuming the
+ // conversion methods are present.
+ @Override
+ public void synthesizeClasses(CfL8ClassSynthesizerEventConsumer eventConsumer) {
DesugaredLibraryConfiguration conf = appView.options().desugaredLibraryConfiguration;
+ List<DexProgramClass> validClassesToWrap = new ArrayList<>();
for (DexType type : conf.getWrapperConversions()) {
assert !conf.getCustomConversions().containsKey(type);
DexClass validClassToWrap = getValidClassToWrap(type);
// In broken set-ups we can end up having a json files containing wrappers of non desugared
// classes. Such wrappers are not required since the class won't be rewritten.
if (validClassToWrap.isProgramClass()) {
- ensureWrappers(validClassToWrap, ignored -> {}, eventConsumer);
+ validClassesToWrap.add(validClassToWrap.asProgramClass());
+ ensureProgramWrappersWithoutVirtualMethods(validClassToWrap, eventConsumer);
}
}
+ for (DexProgramClass validClassToWrap : validClassesToWrap) {
+ ensureProgramWrappersVirtualMethods(validClassToWrap);
+ }
+ }
+
+ // We generate first the two wrappers with the constructor method and the fields, then we
+ // the two conversion methods which requires the wrappers to know both fields.
+ private void ensureProgramWrappersWithoutVirtualMethods(
+ DexClass context, DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer) {
+ assert eventConsumer != null;
+ assert context.isProgramClass();
+ DexType type = context.type;
+ assert appView.options().isDesugaredLibraryCompilation();
+ DexProgramClass programContext = context.asProgramClass();
+ DexClass wrapper =
+ ensureProgramWrapper(
+ SyntheticKind.WRAPPER, vivifiedTypeFor(type), type, programContext, eventConsumer);
+ DexClass vivifiedWrapper =
+ ensureProgramWrapper(
+ SyntheticKind.VIVIFIED_WRAPPER,
+ type,
+ vivifiedTypeFor(type),
+ programContext,
+ eventConsumer);
+ getExistingProgramConversionMethod(
+ SyntheticKind.WRAPPER, programContext, wrapper, vivifiedWrapper);
+ getExistingProgramConversionMethod(
+ SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapper, wrapper);
+ }
+
+ private void ensureProgramWrappersVirtualMethods(DexClass context) {
+ assert context.isProgramClass();
+ DexProgramClass wrapper = getExistingProgramWrapper(context, SyntheticKind.WRAPPER);
+ wrapper.addVirtualMethods(
+ synthesizeVirtualMethodsForTypeWrapper(context, getWrapperUniqueEncodedField(wrapper)));
+ DexProgramClass vivifiedWrapper =
+ getExistingProgramWrapper(context, SyntheticKind.VIVIFIED_WRAPPER);
+ vivifiedWrapper.addVirtualMethods(
+ synthesizeVirtualMethodsForVivifiedTypeWrapper(
+ context, getWrapperUniqueEncodedField(vivifiedWrapper)));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java
new file mode 100644
index 0000000..212ad66
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.graph.DexClasspathClass;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface DesugaredLibraryWrapperSynthesizerEventConsumer {
+
+ interface DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer {
+
+ void acceptWrapperProgramClass(DexProgramClass clazz);
+ }
+
+ interface DesugaredLibraryClasspathWrapperSynthesizeEventConsumer {
+
+ void acceptWrapperClasspathClass(DexClasspathClass clazz);
+ }
+
+ interface DesugaredLibraryAPIConverterEventConsumer
+ extends DesugaredLibraryClasspathWrapperSynthesizeEventConsumer {
+
+ void acceptAPIConversion(ProgramMethod method);
+ }
+
+ interface DesugaredLibraryAPICallbackSynthesizorEventConsumer
+ extends DesugaredLibraryClasspathWrapperSynthesizeEventConsumer {
+
+ void acceptAPIConversionCallback(ProgramMethod method);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizer.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizer.java
index c3fded8..5af4f7e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizer.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizer;
+import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer;
import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming;
@@ -28,13 +30,21 @@
import java.util.Map;
import java.util.Set;
-public final class EmulatedInterfaceProcessor implements InterfaceDesugaringProcessor {
+public final class EmulatedInterfaceSynthesizer implements CfL8ClassSynthesizer {
private final AppView<?> appView;
private final InterfaceDesugaringSyntheticHelper helper;
private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy;
- EmulatedInterfaceProcessor(AppView<?> appView) {
+ public static EmulatedInterfaceSynthesizer create(AppView<?> appView) {
+ if (!appView.options().isDesugaredLibraryCompilation()
+ || appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()) {
+ return null;
+ }
+ return new EmulatedInterfaceSynthesizer(appView);
+ }
+
+ EmulatedInterfaceSynthesizer(AppView<?> appView) {
this.appView = appView;
helper = new InterfaceDesugaringSyntheticHelper(appView);
// Avoid the computation outside L8 since it is not needed.
@@ -83,7 +93,7 @@
}
DexProgramClass ensureEmulateInterfaceLibrary(
- DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+ DexProgramClass emulatedInterface, EmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
assert helper.isEmulatedInterface(emulatedInterface.type);
DexProgramClass emulateInterfaceClass =
appView
@@ -101,7 +111,7 @@
synthesizeEmulatedInterfaceMethod(
method, emulatedInterface, methodBuilder))),
ignored -> {});
- emulateInterfaceClass.forEachProgramMethod(eventConsumer::acceptEmulatedInterfaceMethod);
+ eventConsumer.acceptEmulatedInterface(emulateInterfaceClass);
assert emulateInterfaceClass.getType()
== InterfaceDesugaringSyntheticHelper.getEmulateLibraryInterfaceClassType(
emulatedInterface.type, appView.dexItemFactory());
@@ -209,15 +219,20 @@
}
@Override
- public void process(
- DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
- if (!appView.options().isDesugaredLibraryCompilation()
- || !helper.isEmulatedInterface(emulatedInterface.type)
- || appView.isAlreadyLibraryDesugared(emulatedInterface)) {
- return;
- }
- if (needsEmulateInterfaceLibrary(emulatedInterface)) {
- ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer);
+ public void synthesizeClasses(CfL8ClassSynthesizerEventConsumer 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)) {
+ ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer);
+ }
}
}
@@ -225,20 +240,6 @@
return Iterables.any(emulatedInterface.methods(), DexEncodedMethod::isDefaultMethod);
}
- @Override
- public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
- warnMissingEmulatedInterfaces();
- }
-
- private void warnMissingEmulatedInterfaces() {
- for (DexType interfaceType : helper.getEmulatedInterfaces()) {
- DexClass theInterface = appView.definitionFor(interfaceType);
- if (theInterface == null) {
- warnMissingEmulatedInterface(interfaceType);
- }
- }
- }
-
private void warnMissingEmulatedInterface(DexType interfaceType) {
StringDiagnostic warning =
new StringDiagnostic(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizerEventConsumer.java
new file mode 100644
index 0000000..cb73851
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizerEventConsumer.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, 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.itf;
+
+import com.android.tools.r8.graph.DexProgramClass;
+
+public interface EmulatedInterfaceSynthesizerEventConsumer {
+
+ void acceptEmulatedInterface(DexProgramClass clazz);
+}
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 ad5aa5e..65816d4 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
@@ -4,29 +4,56 @@
package com.android.tools.r8.ir.desugar.itf;
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInitClass;
+import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
+import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexEncodedField;
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.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexValue.DexValueInt;
+import com.android.tools.r8.graph.FieldAccessFlags;
+import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
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.ProgramMethod;
+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.Consumer;
import java.util.function.Predicate;
+import org.objectweb.asm.Opcodes;
public class InterfaceDesugaringSyntheticHelper {
+ // Any interface method desugared code can be version 1.7 at the most.
+ // Note: we always desugar both default/static (v1.8) and private (v9) when targeting api < N.
+ public static final CfVersion MAX_INTERFACE_DESUGARED_CF_VERSION = CfVersion.V1_7;
+
+ public static CfVersion getInterfaceDesugaredCfVersion(CfVersion existing) {
+ return Ordered.min(existing, MAX_INTERFACE_DESUGARED_CF_VERSION);
+ }
+
// Use InterfaceDesugaringForTesting for public accesses in tests.
static final String EMULATE_LIBRARY_CLASS_NAME_SUFFIX = "$-EL";
static final String COMPANION_CLASS_NAME_SUFFIX = "$-CC";
@@ -167,9 +194,11 @@
return ensureMethodOfClasspathCompanionClassStub(companionMethodReference, context, appView);
}
- DexClassAndMethod ensureStaticAsMethodOfCompanionClassStub(DexClassAndMethod method) {
+ DexClassAndMethod ensureStaticAsMethodOfCompanionClassStub(
+ DexClassAndMethod method, Consumer<ProgramMethod> companionClinitConsumer) {
if (method.isProgramMethod()) {
- return ensureStaticAsMethodOfProgramCompanionClassStub(method.asProgramMethod());
+ return ensureStaticAsMethodOfProgramCompanionClassStub(
+ method.asProgramMethod(), companionClinitConsumer);
} else {
ClasspathOrLibraryClass context = method.getHolder().asClasspathOrLibraryClass();
DexMethod companionMethodReference = staticAsMethodOfCompanionClass(method);
@@ -207,7 +236,8 @@
.getCode()
.getCodeAsInlining(syntheticMethod, method.getReference())
: InvalidCode.getInstance());
- });
+ },
+ ignored -> {});
}
ProgramMethod ensurePrivateAsMethodOfProgramCompanionClassStub(ProgramMethod method) {
@@ -239,11 +269,12 @@
.getCode()
.getCodeAsInlining(syntheticMethod, method.getReference())
: InvalidCode.getInstance());
- });
+ },
+ ignored -> {});
}
// Represent a static interface method as a method of companion class.
- final DexMethod staticAsMethodOfCompanionClass(DexClassAndMethod method) {
+ private DexMethod staticAsMethodOfCompanionClass(DexClassAndMethod method) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
DexType companionClassType = getCompanionClassType(method.getHolderType(), dexItemFactory);
DexMethod rewritten = method.getReference().withHolder(companionClassType, dexItemFactory);
@@ -298,7 +329,11 @@
.setCode(DexEncodedMethod::buildEmptyThrowingCfCode));
}
- ProgramMethod ensureStaticAsMethodOfProgramCompanionClassStub(ProgramMethod method) {
+ ProgramMethod ensureStaticAsMethodOfProgramCompanionClassStub(
+ ProgramMethod method, Consumer<ProgramMethod> companionClinitConsumer) {
+ if (!method.getDefinition().isClassInitializer() && method.getHolder().hasClassInitializer()) {
+ ensureCompanionClassInitializesInterface(method.getHolder(), companionClinitConsumer);
+ }
DexMethod companionMethodReference = staticAsMethodOfCompanionClass(method);
DexEncodedMethod definition = method.getDefinition();
return InterfaceProcessor.ensureCompanionMethod(
@@ -323,7 +358,107 @@
.getCode()
.getCodeAsInlining(syntheticMethod, method.getReference())
: InvalidCode.getInstance());
- });
+ },
+ ignored -> {});
+ }
+
+ private void ensureCompanionClassInitializesInterface(
+ DexProgramClass iface, Consumer<ProgramMethod> companionClinitConsumer) {
+ assert hasStaticMethodThatTriggersNonTrivialClassInitializer(iface);
+ InterfaceProcessor.ensureCompanionMethod(
+ iface,
+ appView.dexItemFactory().classConstructorMethodName,
+ appView.dexItemFactory().createProto(appView.dexItemFactory().voidType),
+ appView,
+ methodBuilder -> createCompanionClassInitializer(iface, methodBuilder),
+ companionClinitConsumer);
+ }
+
+ private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization(
+ DexProgramClass iface) {
+ DexEncodedField clinitField =
+ findExistingStaticClinitFieldToTriggerInterfaceInitialization(iface);
+ if (clinitField == null) {
+ clinitField = createStaticClinitFieldToTriggerInterfaceInitialization(iface);
+ iface.appendStaticField(clinitField);
+ }
+ return clinitField;
+ }
+
+ private boolean hasStaticMethodThatTriggersNonTrivialClassInitializer(DexProgramClass iface) {
+ return iface.hasClassInitializer()
+ && iface
+ .getMethodCollection()
+ .hasDirectMethods(method -> method.isStatic() && !method.isClassInitializer());
+ }
+
+ private DexEncodedField findExistingStaticClinitFieldToTriggerInterfaceInitialization(
+ DexProgramClass iface) {
+ // Don't select a field that has been marked dead, since we'll assert later that these fields
+ // have been dead code eliminated.
+ for (DexEncodedField field :
+ iface.staticFields(field -> !field.isPrivate() && !field.getOptimizationInfo().isDead())) {
+ return field;
+ }
+ return null;
+ }
+
+ private DexEncodedField createStaticClinitFieldToTriggerInterfaceInitialization(
+ DexProgramClass iface) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ DexField clinitFieldReference =
+ dexItemFactory.createFreshFieldNameWithoutHolder(
+ iface.getType(),
+ dexItemFactory.intType,
+ "$desugar$clinit",
+ candidate -> iface.lookupField(candidate) == null);
+ return new DexEncodedField(
+ clinitFieldReference,
+ FieldAccessFlags.builder().setPackagePrivate().setStatic().setSynthetic().build(),
+ FieldTypeSignature.noSignature(),
+ DexAnnotationSet.empty(),
+ DexValueInt.DEFAULT);
+ }
+
+ private void createCompanionClassInitializer(
+ DexProgramClass iface, SyntheticMethodBuilder methodBuilder) {
+ methodBuilder
+ .setAccessFlags(
+ MethodAccessFlags.builder().setConstructor().setPackagePrivate().setStatic().build())
+ .setClassFileVersion(getInterfaceDesugaredCfVersion(iface.getInitialClassFileVersion()))
+ .setCode(
+ method -> {
+ if (appView.canUseInitClass()) {
+ return new CfCode(
+ method.holder,
+ 1,
+ 0,
+ ImmutableList.of(
+ new CfInitClass(iface.getType()),
+ new CfStackInstruction(Opcode.Pop),
+ new CfReturnVoid()),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+ DexEncodedField clinitField =
+ ensureStaticClinitFieldToTriggerInterfaceInitialization(iface);
+ boolean isWide = clinitField.getType().isWideType();
+ return new CfCode(
+ method.holder,
+ isWide ? 2 : 1,
+ 0,
+ ImmutableList.of(
+ new CfFieldInstruction(
+ Opcodes.GETSTATIC,
+ clinitField.getReference(),
+ clinitField.getReference()),
+ isWide
+ ? new CfStackInstruction(Opcode.Pop2)
+ : new CfStackInstruction(Opcode.Pop),
+ new CfReturnVoid()),
+ ImmutableList.of(),
+ ImmutableList.of());
+ });
}
private Predicate<DexType> getShouldIgnoreFromReportsPredicate(AppView<?> appView) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java
index 031e142..bdc8816 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java
@@ -12,5 +12,7 @@
void acceptInvokeStaticInterfaceOutliningMethod(ProgramMethod method, ProgramMethod context);
+ void acceptCompanionClassClinit(ProgramMethod method);
+
// TODO(b/183998768): Add acceptCompanionClass and acceptEmulatedInterface.
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
index fafc920..f989858 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
@@ -35,10 +35,6 @@
private List<InterfaceDesugaringProcessor> instantiateInterfaceDesugaringProcessors(
AppView<?> appView) {
- // During L8 compilation, emulated interfaces are processed to be renamed, to have
- // their interfaces fixed-up and to generate the emulated dispatch code.
- EmulatedInterfaceProcessor emulatedInterfaceProcessor = new EmulatedInterfaceProcessor(appView);
-
// Process all classes first. Add missing forwarding methods to
// replace desugared default interface methods.
ClassProcessor classProcessor = new ClassProcessor(appView);
@@ -50,7 +46,7 @@
InterfaceProcessor interfaceProcessor = new InterfaceProcessor(appView);
// The processors can be listed in any order.
- return ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor);
+ return ImmutableList.of(classProcessor, interfaceProcessor);
}
/** Runs the interfaceProcessor, the class processor and the emulated interface processor. */
@@ -81,12 +77,6 @@
sortedSynthesizedMethods.add(method);
}
- @Override
- public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
-
- sortedSynthesizedMethods.add(method);
- }
-
public SortedProgramMethodSet getSortedSynthesizedMethods() {
return sortedSynthesizedMethods;
}
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 38ad3e4..dfdfb45 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
@@ -464,7 +464,8 @@
context,
staticOutliningMethodConsumer,
rewriteInvoke,
- rewriteToThrow);
+ rewriteToThrow,
+ eventConsumer::acceptCompanionClassClinit);
}
assert invoke.isInvokeSpecial();
if (invoke.isInvokeSuper(context.getHolderType())) {
@@ -665,7 +666,8 @@
context,
synthesizedMethods::add,
rewriteInvoke,
- rewriteToThrow);
+ rewriteToThrow,
+ synthesizedMethods::add);
} else {
assert instruction.isInvokeSuper();
rewriteInvokeSuper(invoke.getInvokedMethod(), context, rewriteInvoke, rewriteToThrow);
@@ -761,7 +763,8 @@
ProgramMethod context,
Consumer<ProgramMethod> staticOutliningMethodConsumer,
Function<DexMethod, Collection<CfInstruction>> rewriteInvoke,
- Function<SingleResolutionResult, Collection<CfInstruction>> rewriteToThrow) {
+ Function<SingleResolutionResult, Collection<CfInstruction>> rewriteToThrow,
+ Consumer<ProgramMethod> companionClinitConsumer) {
if (appView.getSyntheticItems().isPendingSynthetic(invokedMethod.holder)) {
// We did not create this code yet, but it will not require rewriting.
return null;
@@ -856,7 +859,8 @@
assert resolutionResult.getResolvedMethod().isStatic();
assert invokeNeedsRewriting(invokedMethod, STATIC);
DexClassAndMethod companionMethod =
- helper.ensureStaticAsMethodOfCompanionClassStub(resolutionResult.getResolutionPair());
+ helper.ensureStaticAsMethodOfCompanionClassStub(
+ resolutionResult.getResolutionPair(), companionClinitConsumer);
return rewriteInvoke.apply(companionMethod.getReference());
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
index 2581364..8fc50d1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
@@ -10,7 +10,6 @@
void acceptForwardingMethod(ProgramMethod method);
+ // TODO(b/183998768): Remove this once interface desugaring is moved to the R8 enqueuer.
void acceptCompanionClassClinit(ProgramMethod method);
-
- void acceptEmulatedInterfaceMethod(ProgramMethod method);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index c917520..1437d48 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -5,37 +5,25 @@
package com.android.tools.r8.ir.desugar.itf;
-import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.cf.code.CfReturnVoid;
-import com.android.tools.r8.cf.code.CfStackInstruction;
-import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.InvokeSuper;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
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.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
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.DexValue.DexValueInt;
-import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InvalidCode;
-import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodCollection;
import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -48,7 +36,6 @@
import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
-import com.google.common.collect.ImmutableList;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
@@ -59,7 +46,6 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
-import org.objectweb.asm.Opcodes;
// Default and static method interface desugaring processor for interfaces.
//
@@ -101,12 +87,11 @@
private void ensureCompanionClassMethods(
DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
- ensureCompanionClassInitializesInterface(iface, eventConsumer);
// TODO(b/183998768): Once fixed, the methods should be added for processing.
// D8 and R8 don't need to optimize the methods since they are just moved from interfaces and
// don't need to be re-processed.
processVirtualInterfaceMethods(iface);
- processDirectInterfaceMethods(iface);
+ processDirectInterfaceMethods(iface, eventConsumer);
}
static ProgramMethod ensureCompanionMethod(
@@ -114,7 +99,8 @@
DexString methodName,
DexProto methodProto,
AppView<?> appView,
- Consumer<SyntheticMethodBuilder> fn) {
+ Consumer<SyntheticMethodBuilder> methodBuilderCallback,
+ Consumer<ProgramMethod> newMethodCallback) {
return appView
.getSyntheticItems()
.ensureFixedClassMethod(
@@ -131,93 +117,8 @@
.getClassSignature()
.toObjectBoundWithSameFormals(
new ClassTypeSignature(appView.dexItemFactory().objectType))),
- fn);
- }
-
- private void ensureCompanionClassInitializesInterface(
- DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
- if (!hasStaticMethodThatTriggersNonTrivialClassInitializer(iface)) {
- return;
- }
- DexEncodedField clinitField = ensureStaticClinitFieldToTriggerInterfaceInitialization(iface);
- ProgramMethod clinit =
- ensureCompanionMethod(
- iface,
- appView.dexItemFactory().classConstructorMethodName,
- appView.dexItemFactory().createProto(appView.dexItemFactory().voidType),
- appView,
- methodBuilder -> createCompanionClassInitializer(iface, clinitField, methodBuilder));
- eventConsumer.acceptCompanionClassClinit(clinit);
- }
-
- private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization(
- DexProgramClass iface) {
- DexEncodedField clinitField =
- findExistingStaticClinitFieldToTriggerInterfaceInitialization(iface);
- if (clinitField == null) {
- clinitField = createStaticClinitFieldToTriggerInterfaceInitialization(iface);
- iface.appendStaticField(clinitField);
- }
- return clinitField;
- }
-
- private boolean hasStaticMethodThatTriggersNonTrivialClassInitializer(DexProgramClass iface) {
- return iface.hasClassInitializer()
- && iface
- .getMethodCollection()
- .hasDirectMethods(method -> method.isStatic() && !method.isClassInitializer());
- }
-
- private DexEncodedField findExistingStaticClinitFieldToTriggerInterfaceInitialization(
- DexProgramClass iface) {
- // Don't select a field that has been marked dead, since we'll assert later that these fields
- // have been dead code eliminated.
- for (DexEncodedField field :
- iface.staticFields(field -> !field.isPrivate() && !field.getOptimizationInfo().isDead())) {
- return field;
- }
- return null;
- }
-
- private DexEncodedField createStaticClinitFieldToTriggerInterfaceInitialization(
- DexProgramClass iface) {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- DexField clinitFieldReference =
- dexItemFactory.createFreshFieldNameWithoutHolder(
- iface.getType(),
- dexItemFactory.intType,
- "$desugar$clinit",
- candidate -> iface.lookupField(candidate) == null);
- return new DexEncodedField(
- clinitFieldReference,
- FieldAccessFlags.builder().setPackagePrivate().setStatic().setSynthetic().build(),
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexValueInt.DEFAULT);
- }
-
- private void createCompanionClassInitializer(
- DexProgramClass iface, DexEncodedField clinitField, SyntheticMethodBuilder methodBuilder) {
- SyntheticMethodBuilder.SyntheticCodeGenerator codeGenerator =
- method ->
- new CfCode(
- method.holder,
- clinitField.getType().isWideType() ? 2 : 1,
- 0,
- ImmutableList.of(
- new CfFieldInstruction(
- Opcodes.GETSTATIC, clinitField.getReference(), clinitField.getReference()),
- clinitField.getType().isWideType()
- ? new CfStackInstruction(Opcode.Pop2)
- : new CfStackInstruction(Opcode.Pop),
- new CfReturnVoid()),
- ImmutableList.of(),
- ImmutableList.of());
- methodBuilder
- .setAccessFlags(
- MethodAccessFlags.builder().setConstructor().setPackagePrivate().setStatic().build())
- .setCode(codeGenerator)
- .setClassFileVersion(iface.getInitialClassFileVersion());
+ methodBuilderCallback,
+ newMethodCallback);
}
private void processVirtualInterfaceMethods(DexProgramClass iface) {
@@ -248,7 +149,8 @@
}
}
- private void processDirectInterfaceMethods(DexProgramClass iface) {
+ private void processDirectInterfaceMethods(
+ DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
for (ProgramMethod method : iface.directProgramMethods()) {
DexEncodedMethod definition = method.getDefinition();
if (definition.isClassInitializer()) {
@@ -271,7 +173,9 @@
+ " is expected to "
+ "either be public or private in "
+ iface.origin;
- companion = helper.ensureStaticAsMethodOfProgramCompanionClassStub(method);
+ companion =
+ helper.ensureStaticAsMethodOfProgramCompanionClassStub(
+ method, eventConsumer::acceptCompanionClassClinit);
} else {
assert definition.isPrivate();
Code code = definition.getCode();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
index 9266ad9..8814c2e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
@@ -38,6 +38,8 @@
.build())
.setMethod(bridgeMethodReference)
.setD8R8Synthesized()
+ .setApiLevelForDefinition(field.getDefinition().getApiLevel())
+ .setApiLevelForCode(field.getDefinition().getApiLevel())
.build());
}
@@ -59,6 +61,8 @@
.build())
.setMethod(bridgeMethodReference)
.setD8R8Synthesized()
+ .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
+ .setApiLevelForCode(method.getDefinition().getApiLevelForCode())
.build());
}
@@ -87,6 +91,8 @@
builder -> builder.setDirectTarget(method.getReference(), isInterface))
.build())
.setMethod(bridgeMethodReference)
+ .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
+ .setApiLevelForCode(method.getDefinition().getApiLevelForDefinition())
.setD8R8Synthesized()
.build());
}
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 a5ed9fb..2e74bb2 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
@@ -33,7 +33,9 @@
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.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
@@ -61,6 +63,7 @@
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.InstanceGet;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InvokeCustom;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeVirtual;
@@ -122,6 +125,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -217,6 +221,13 @@
}
private DexProgramClass getEnumUnboxingCandidateOrNull(DexType type) {
+ if (type.isArrayType()) {
+ return getEnumUnboxingCandidateOrNull(type.toBaseType(appView.dexItemFactory()));
+ }
+ if (type.isPrimitiveType() || type.isVoidType()) {
+ return null;
+ }
+ assert type.isClassType();
return enumUnboxingCandidatesInfo.getCandidateClassOrNull(type);
}
@@ -253,6 +264,9 @@
case Opcodes.CHECK_CAST:
analyzeCheckCast(instruction.asCheckCast(), eligibleEnums);
break;
+ case Opcodes.INVOKE_CUSTOM:
+ analyzeInvokeCustom(instruction.asInvokeCustom(), eligibleEnums);
+ break;
case INVOKE_STATIC:
analyzeInvokeStatic(instruction.asInvokeStatic(), eligibleEnums, code.context());
break;
@@ -289,6 +303,49 @@
}
}
+ private void analyzeInvokeCustom(InvokeCustom invoke, Set<DexType> eligibleEnums) {
+ Consumer<DexType> typeReferenceConsumer =
+ type -> {
+ DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(type);
+ if (enumClass != null) {
+ eligibleEnums.add(enumClass.getType());
+ }
+ };
+ invoke.getCallSite().getMethodProto().forEachType(typeReferenceConsumer);
+ invoke
+ .getCallSite()
+ .getBootstrapArgs()
+ .forEach(
+ bootstrapArgument -> {
+ if (bootstrapArgument.isDexValueMethodHandle()) {
+ DexMethodHandle methodHandle =
+ bootstrapArgument.asDexValueMethodHandle().getValue();
+ if (methodHandle.isMethodHandle()) {
+ DexMethod method = methodHandle.asMethod();
+ DexProgramClass enumClass =
+ getEnumUnboxingCandidateOrNull(method.getHolderType());
+ if (enumClass != null) {
+ markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass);
+ } else {
+ method.getProto().forEachType(typeReferenceConsumer);
+ }
+ } else {
+ assert methodHandle.isFieldHandle();
+ DexField field = methodHandle.asField();
+ DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(field.getHolderType());
+ if (enumClass != null) {
+ markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass);
+ } else {
+ typeReferenceConsumer.accept(field.getType());
+ }
+ }
+ } else if (bootstrapArgument.isDexValueMethodType()) {
+ DexProto proto = bootstrapArgument.asDexValueMethodType().getValue();
+ proto.forEachType(typeReferenceConsumer);
+ }
+ });
+ }
+
private void analyzeFieldInstruction(
FieldInstruction fieldInstruction, Set<DexType> eligibleEnums, ProgramMethod context) {
DexField field = fieldInstruction.getField();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
index 7a95765..9614ede 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.optimize.enums;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.cf.code.CfArrayStore;
@@ -48,7 +48,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.function.Function;
import org.objectweb.asm.Opcodes;
public class SharedEnumUnboxingUtilityClass extends EnumUnboxingUtilityClass {
@@ -238,7 +237,7 @@
DexEncodedField.NO_STATIC_VALUE,
DexEncodedField.NOT_DEPRECATED,
DexEncodedField.D8_R8_SYNTHESIZED,
- getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+ minApiLevelIfEnabledOrUnknown(appView));
fieldAccessInfoCollectionModifierBuilder
.recordFieldReadInUnknownContext(valuesField.getReference())
.recordFieldWriteInUnknownContext(valuesField.getReference());
@@ -258,8 +257,8 @@
createClassInitializerCode(sharedUtilityClassType, valuesField),
DexEncodedMethod.D8_R8_SYNTHESIZED,
CfVersion.V1_6,
- getApiLevelIfEnabledForNewMember(appView, Function.identity()),
- getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+ minApiLevelIfEnabledOrUnknown(appView),
+ minApiLevelIfEnabledOrUnknown(appView));
}
private CfCode createClassInitializerCode(
@@ -305,8 +304,8 @@
createValuesMethodCode(sharedUtilityClassType, valuesField),
DexEncodedMethod.D8_R8_SYNTHESIZED,
CfVersion.V1_6,
- getApiLevelIfEnabledForNewMember(appView, Function.identity()),
- getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+ minApiLevelIfEnabledOrUnknown(appView),
+ minApiLevelIfEnabledOrUnknown(appView));
this.valuesMethod = valuesMethod;
return valuesMethod;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
index 429bdae..bac0275 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
@@ -26,6 +26,7 @@
public static final Reason INVALID_INVOKE = new StringReason("INVALID_INVOKE");
public static final Reason INVALID_INVOKE_CLASSPATH =
new StringReason("INVALID_INVOKE_CLASSPATH");
+ public static final Reason INVALID_INVOKE_CUSTOM = new StringReason("INVALID_INVOKE_CUSTOM");
public static final Reason INVALID_INVOKE_ON_ARRAY = new StringReason("INVALID_INVOKE_ON_ARRAY");
public static final Reason IMPLICIT_UP_CAST_IN_RETURN =
new StringReason("IMPLICIT_UP_CAST_IN_RETURN");
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
index 4fd2fcd..c790a02 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
-import com.android.tools.r8.utils.AndroidApiLevel;
public class DefaultFieldOptimizationInfo extends FieldOptimizationInfo {
@@ -56,11 +55,6 @@
}
@Override
- public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
- throw new RuntimeException("Should never be called");
- }
-
- @Override
public MutableFieldOptimizationInfo toMutableOptimizationInfo() {
return new MutableFieldOptimizationInfo();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
deleted file mode 100644
index a9c7462..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
+++ /dev/null
@@ -1,35 +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.ir.optimize.info;
-
-import com.android.tools.r8.utils.AndroidApiLevel;
-
-public class DefaultFieldOptimizationWithMinApiInfo extends DefaultFieldOptimizationInfo {
-
- private static final DefaultFieldOptimizationWithMinApiInfo INSTANCE =
- new DefaultFieldOptimizationWithMinApiInfo();
-
- public static DefaultFieldOptimizationWithMinApiInfo getInstance() {
- return INSTANCE;
- }
-
- @Override
- public boolean hasApiReferenceLevelForDefinition() {
- return true;
- }
-
- @Override
- public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
- return minApi;
- }
-
- @Override
- public MutableFieldOptimizationInfo toMutableOptimizationInfo() {
- MutableFieldOptimizationInfo updatableFieldOptimizationInfo = super.toMutableOptimizationInfo();
- // Use null to specify that the min api is set to minApi.
- updatableFieldOptimizationInfo.setMinApiReferenceLevel();
- return updatableFieldOptimizationInfo;
- }
-}
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 31ecb9b..24aeb3d 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,7 +18,6 @@
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
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.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableSet;
import java.util.BitSet;
@@ -196,26 +195,6 @@
}
@Override
- public boolean hasApiReferenceLevelForCode() {
- return false;
- }
-
- @Override
- public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
- throw new RuntimeException("Should never be called");
- }
-
- @Override
- public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
- throw new RuntimeException("Should never be called");
- }
-
- @Override
- public boolean hasApiReferenceLevelForDefinition() {
- return false;
- }
-
- @Override
public MutableMethodOptimizationInfo toMutableOptimizationInfo() {
return new MutableMethodOptimizationInfo();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
deleted file mode 100644
index cd06dee..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2021, 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.optimize.info;
-
-import com.android.tools.r8.utils.AndroidApiLevel;
-
-public class DefaultMethodOptimizationWithMinApiInfo extends DefaultMethodOptimizationInfo {
-
- private static final DefaultMethodOptimizationWithMinApiInfo DEFAULT_MIN_API_INSTANCE =
- new DefaultMethodOptimizationWithMinApiInfo();
-
- public static DefaultMethodOptimizationWithMinApiInfo getInstance() {
- return DEFAULT_MIN_API_INSTANCE;
- }
-
- @Override
- public boolean hasApiReferenceLevelForDefinition() {
- return true;
- }
-
- @Override
- public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
- return minApi;
- }
-
- @Override
- public boolean hasApiReferenceLevelForCode() {
- return true;
- }
-
- @Override
- public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
- return minApi;
- }
-
- @Override
- public MutableMethodOptimizationInfo toMutableOptimizationInfo() {
- MutableMethodOptimizationInfo updatableMethodOptimizationInfo =
- super.toMutableOptimizationInfo();
- // Use null to specify that the min api is set to minApi.
- updatableMethodOptimizationInfo.setMinApiReferenceLevel();
- return updatableMethodOptimizationInfo;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
index 9cb8a2a..f5242e9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.ir.optimize.info;
-import com.android.tools.r8.utils.AndroidApiLevel;
-
public interface MemberOptimizationInfo<
T extends MemberOptimizationInfo<T> & MutableOptimizationInfo> {
@@ -21,12 +19,6 @@
return null;
}
- default boolean hasApiReferenceLevelForDefinition() {
- return false;
- }
-
- AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi);
-
T toMutableOptimizationInfo();
default boolean isFieldOptimizationInfo() {
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 bb45fbc..aab9aa6 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,7 +15,6 @@
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
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.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import java.util.BitSet;
import java.util.Set;
@@ -101,10 +100,6 @@
public abstract boolean returnValueHasBeenPropagated();
- public abstract boolean hasApiReferenceLevelForCode();
-
- public abstract AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi);
-
@Override
public boolean isMethodOptimizationInfo() {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index bdab6e8..9150ea0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -15,8 +15,6 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import java.util.Optional;
import java.util.Set;
/**
@@ -38,7 +36,6 @@
private int readBits = 0;
private ClassTypeElement dynamicLowerBoundType = null;
private TypeElement dynamicUpperBoundType = null;
- private Optional<AndroidApiLevel> apiReferenceLevel = null;
public MutableFieldOptimizationInfo fixupClassTypeReferences(
AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
@@ -69,7 +66,6 @@
public MutableFieldOptimizationInfo mutableCopy() {
MutableFieldOptimizationInfo copy = new MutableFieldOptimizationInfo();
copy.flags = flags;
- copy.apiReferenceLevel = apiReferenceLevel;
return copy;
}
@@ -154,29 +150,4 @@
public MutableFieldOptimizationInfo asMutableFieldOptimizationInfo() {
return this;
}
-
- @SuppressWarnings("OptionalAssignedToNull")
- @Override
- public boolean hasApiReferenceLevelForDefinition() {
- return apiReferenceLevel != null;
- }
-
- @Override
- public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
- assert hasApiReferenceLevelForDefinition();
- return apiReferenceLevel.orElse(minApi);
- }
-
- @Override
- @SuppressWarnings("OptionalAssignedToNull")
- public void setMinApiReferenceLevel() {
- assert apiReferenceLevel == null;
- this.apiReferenceLevel = Optional.empty();
- }
-
- @Override
- public void setApiReferenceLevelForDefinition(AndroidApiLevel apiReferenceLevel) {
- assert apiReferenceLevel != null;
- this.apiReferenceLevel = Optional.of(apiReferenceLevel);
- }
}
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 54184d78..3efe7f6 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
@@ -25,11 +25,9 @@
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.util.BitSet;
-import java.util.Optional;
import java.util.Set;
public class MutableMethodOptimizationInfo extends MethodOptimizationInfo
@@ -75,9 +73,6 @@
private SimpleInliningConstraint simpleInliningConstraint =
NeverSimpleInliningConstraint.getInstance();
- private Optional<AndroidApiLevel> codeApiReferenceLevel = null;
- private Optional<AndroidApiLevel> definitionApiReferenceLevel = null;
-
// To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are
// merged into a flag int field. The various static final FLAG fields indicate which bit is
// used by each boolean. DEFAULT_FLAGS encodes the default value for efficient instantiation and
@@ -159,8 +154,6 @@
nonNullParamOnNormalExits = template.nonNullParamOnNormalExits;
classInlinerConstraint = template.classInlinerConstraint;
enumUnboxerMethodClassification = template.enumUnboxerMethodClassification;
- definitionApiReferenceLevel = template.definitionApiReferenceLevel;
- codeApiReferenceLevel = template.codeApiReferenceLevel;
}
public MutableMethodOptimizationInfo fixupClassTypeReferences(
@@ -536,50 +529,6 @@
}
@Override
- public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
- assert hasApiReferenceLevelForDefinition();
- return definitionApiReferenceLevel.orElse(minApi);
- }
-
- @SuppressWarnings("OptionalAssignedToNull")
- @Override
- public boolean hasApiReferenceLevelForDefinition() {
- return definitionApiReferenceLevel != null;
- }
-
- @Override
- @SuppressWarnings("OptionalAssignedToNull")
- public boolean hasApiReferenceLevelForCode() {
- return codeApiReferenceLevel != null;
- }
-
- @Override
- public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
- assert hasApiReferenceLevelForCode();
- return codeApiReferenceLevel.orElse(minApi);
- }
-
- @Override
- @SuppressWarnings("OptionalAssignedToNull")
- public void setMinApiReferenceLevel() {
- assert codeApiReferenceLevel == null;
- assert definitionApiReferenceLevel == null;
- this.codeApiReferenceLevel = Optional.empty();
- this.definitionApiReferenceLevel = Optional.empty();
- }
-
- public void setApiReferenceLevelForCode(AndroidApiLevel apiLevel) {
- assert apiLevel != null;
- this.codeApiReferenceLevel = Optional.of(apiLevel);
- }
-
- @Override
- public void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel) {
- assert apiLevel != null;
- this.definitionApiReferenceLevel = Optional.of(apiLevel);
- }
-
- @Override
public boolean isMutableOptimizationInfo() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
index 421f689..58f5470 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
@@ -4,11 +4,6 @@
package com.android.tools.r8.ir.optimize.info;
-import com.android.tools.r8.utils.AndroidApiLevel;
-
public interface MutableOptimizationInfo {
- void setMinApiReferenceLevel();
-
- void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
index 4b7cffb..1e518d6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
@@ -177,11 +177,14 @@
instructionIterator.removeOrReplaceByDebugLocalRead();
} else if (inValue.isAlwaysNull(appView)) {
if (singleTarget.getReference() == objectsMethods.requireNonNullElse) {
- // Optimize Objects.requireNonNullElse(null, defaultObj) into defaultObj.
- if (invoke.hasOutValue()) {
- invoke.outValue().replaceUsers(invoke.getLastArgument(), affectedValues);
+ // Optimize Objects.requireNonNullElse(null, defaultObj) into defaultObj if defaultObj
+ // is never null.
+ if (invoke.getLastArgument().isNeverNull()) {
+ if (invoke.hasOutValue()) {
+ invoke.outValue().replaceUsers(invoke.getLastArgument(), affectedValues);
+ }
+ instructionIterator.removeOrReplaceByDebugLocalRead();
}
- instructionIterator.removeOrReplaceByDebugLocalRead();
} else if (singleTarget.getReference() == objectsMethods.requireNonNullElseGet) {
// Don't optimize Objects.requireNonNullElseGet. The result of calling supplier.get() still
// needs a null-check, so two invokes will be needed.
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 4ce1fb6..7395cbf 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -32,8 +32,8 @@
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.collections.ImmutableDeque;
import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
@@ -58,21 +58,18 @@
private final DexMethod forwardMethod;
private final DesugaredLibraryWrapperSynthesizer wrapperSynthesizer;
private final boolean itfCall;
- private final DesugaredLibraryAPIConverterEventConsumer eventConsumer;
public APIConverterVivifiedWrapperCfCodeProvider(
AppView<?> appView,
DexMethod forwardMethod,
DexField wrapperField,
DesugaredLibraryWrapperSynthesizer wrapperSynthesizer,
- boolean itfCall,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
+ boolean itfCall) {
super(appView, wrapperField.holder);
this.forwardMethod = forwardMethod;
this.wrapperField = wrapperField;
this.wrapperSynthesizer = wrapperSynthesizer;
this.itfCall = itfCall;
- this.eventConsumer = eventConsumer;
}
@Override
@@ -93,8 +90,8 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- wrapperSynthesizer.ensureConversionMethod(
- param, param, vivifiedTypeFor(param), eventConsumer),
+ wrapperSynthesizer.getExistingProgramConversionMethod(
+ param, param, vivifiedTypeFor(param)),
false));
newParameters[index - 1] = vivifiedTypeFor(param);
}
@@ -125,8 +122,8 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- wrapperSynthesizer.ensureConversionMethod(
- returnType, vivifiedTypeFor(returnType), returnType, eventConsumer),
+ wrapperSynthesizer.getExistingProgramConversionMethod(
+ returnType, vivifiedTypeFor(returnType), returnType),
false));
}
if (returnType == factory.voidType) {
@@ -138,31 +135,29 @@
}
}
- public static class APIConverterWrapperCfCodeProvider
+ public abstract static class AbstractAPIConverterWrapperCfCodeProvider
extends DesugaredLibraryAPIConversionCfCodeProvider {
- DexField wrapperField;
DexMethod forwardMethod;
DesugaredLibraryWrapperSynthesizer wrapperSynthesizor;
boolean itfCall;
- private final DesugaredLibraryAPIConverterEventConsumer eventConsumer;
- public APIConverterWrapperCfCodeProvider(
+ public AbstractAPIConverterWrapperCfCodeProvider(
AppView<?> appView,
+ DexType holder,
DexMethod forwardMethod,
- DexField wrapperField,
DesugaredLibraryWrapperSynthesizer wrapperSynthesizor,
- boolean itfCall,
- DesugaredLibraryAPIConverterEventConsumer eventConsumer) {
- // Var wrapperField is null if should forward to receiver.
- super(appView, wrapperField == null ? forwardMethod.holder : wrapperField.holder);
+ boolean itfCall) {
+ super(appView, holder);
this.forwardMethod = forwardMethod;
- this.wrapperField = wrapperField;
this.wrapperSynthesizor = wrapperSynthesizor;
this.itfCall = itfCall;
- this.eventConsumer = eventConsumer;
}
+ abstract void generatePushReceiver(List<CfInstruction> instructions);
+
+ abstract DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType);
+
@Override
public CfCode generateCfCode() {
DexItemFactory factory = appView.dexItemFactory();
@@ -170,13 +165,7 @@
// Wrapped value is a type. Method uses vivifiedTypes as external. Forward method should
// use types.
- // Var wrapperField is null if should forward to receiver.
- if (wrapperField == null) {
- instructions.add(new CfLoad(ValueType.fromDexType(forwardMethod.holder), 0));
- } else {
- instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
- instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, wrapperField, wrapperField));
- }
+ generatePushReceiver(instructions);
int stackIndex = 1;
for (DexType param : forwardMethod.proto.parameters.values) {
instructions.add(new CfLoad(ValueType.fromDexType(param), stackIndex));
@@ -184,8 +173,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- wrapperSynthesizor.ensureConversionMethod(
- param, vivifiedTypeFor(param), param, eventConsumer),
+ ensureConversionMethod(param, vivifiedTypeFor(param), param),
false));
}
if (param == factory.longType || param == factory.doubleType) {
@@ -205,8 +193,7 @@
instructions.add(
new CfInvoke(
Opcodes.INVOKESTATIC,
- wrapperSynthesizor.ensureConversionMethod(
- returnType, returnType, vivifiedTypeFor(returnType), eventConsumer),
+ ensureConversionMethod(returnType, returnType, vivifiedTypeFor(returnType)),
false));
returnType = vivifiedTypeFor(returnType);
}
@@ -219,6 +206,59 @@
}
}
+ public static class APICallbackWrapperCfCodeProvider
+ extends AbstractAPIConverterWrapperCfCodeProvider {
+
+ private final DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer;
+
+ public APICallbackWrapperCfCodeProvider(
+ AppView<?> appView,
+ DexMethod forwardMethod,
+ DesugaredLibraryWrapperSynthesizer wrapperSynthesizor,
+ boolean itfCall,
+ DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) {
+ super(appView, forwardMethod.holder, forwardMethod, wrapperSynthesizor, itfCall);
+ this.eventConsumer = eventConsumer;
+ }
+
+ @Override
+ void generatePushReceiver(List<CfInstruction> instructions) {
+ instructions.add(new CfLoad(ValueType.fromDexType(forwardMethod.holder), 0));
+ }
+
+ @Override
+ DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) {
+ return wrapperSynthesizor.ensureConversionMethod(type, srcType, destType, eventConsumer);
+ }
+ }
+
+ public static class APIConverterWrapperCfCodeProvider
+ extends AbstractAPIConverterWrapperCfCodeProvider {
+
+ private final DexField wrapperField;
+
+ public APIConverterWrapperCfCodeProvider(
+ AppView<?> appView,
+ DexMethod forwardMethod,
+ DexField wrapperField,
+ DesugaredLibraryWrapperSynthesizer wrapperSynthesizor,
+ boolean itfCall) {
+ super(appView, wrapperField.holder, forwardMethod, wrapperSynthesizor, itfCall);
+ this.wrapperField = wrapperField;
+ }
+
+ @Override
+ void generatePushReceiver(List<CfInstruction> instructions) {
+ instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
+ instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, wrapperField, wrapperField));
+ }
+
+ @Override
+ DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) {
+ return wrapperSynthesizor.getExistingProgramConversionMethod(type, srcType, destType);
+ }
+ }
+
public static class APIConverterWrapperConversionCfCodeProvider extends SyntheticCfCodeProvider {
DexField reverseWrapperField;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
index 373a5d2..6f34ad1 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -68,7 +68,7 @@
private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) {
return new KotlinAnnotationClassValueInfo(
- KotlinTypeReference.fromBinaryName(arg.getClassName(), factory),
+ KotlinTypeReference.fromBinaryName(arg.getClassName(), factory, arg.getClassName()),
arg.getArrayDimensionCount());
}
@@ -100,7 +100,8 @@
private static KotlinAnnotationEnumValueInfo create(EnumValue arg, DexItemFactory factory) {
return new KotlinAnnotationEnumValueInfo(
- KotlinTypeReference.fromBinaryName(arg.getEnumClassName(), factory),
+ KotlinTypeReference.fromBinaryName(
+ arg.getEnumClassName(), factory, arg.getEnumClassName()),
arg.getEnumEntryName());
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
index cbdd76e..d21cfb1 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -34,7 +34,8 @@
static KotlinAnnotationInfo create(KmAnnotation annotation, DexItemFactory factory) {
return new KotlinAnnotationInfo(
- KotlinTypeReference.fromBinaryName(annotation.getClassName(), factory),
+ KotlinTypeReference.fromBinaryName(
+ annotation.getClassName(), factory, annotation.getClassName()),
KotlinAnnotationArgumentInfo.create(annotation.getArguments(), factory));
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
index aa3731f..9e7d703 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -187,7 +187,8 @@
KmClass kmClass, DexItemFactory factory) {
String anonymousObjectOriginName = JvmExtensionsKt.getAnonymousObjectOriginName(kmClass);
if (anonymousObjectOriginName != null) {
- return KotlinTypeReference.fromBinaryName(anonymousObjectOriginName, factory);
+ return KotlinTypeReference.fromBinaryName(
+ anonymousObjectOriginName, factory, anonymousObjectOriginName);
}
return null;
}
@@ -198,7 +199,7 @@
for (String nestedClass : nestedClasses) {
String binaryName =
clazz.type.toBinaryName() + DescriptorUtils.INNER_CLASS_SEPARATOR + nestedClass;
- nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
+ nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, nestedClass));
}
return nestedTypes.build();
}
@@ -210,7 +211,7 @@
String binaryName =
sealedSubClass.replace(
DescriptorUtils.JAVA_PACKAGE_SEPARATOR, DescriptorUtils.INNER_CLASS_SEPARATOR);
- sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
+ sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, sealedSubClass));
}
return sealedTypes.build();
}
@@ -326,30 +327,31 @@
}
// Rewrite nested classes.
for (KotlinTypeReference nestedClass : nestedClasses) {
- rewritten |=
+ Box<String> nestedDescriptorBox = new Box<>();
+ boolean nestedClassRewritten =
nestedClass.toRenamedBinaryNameOrDefault(
- nestedDescriptor -> {
- if (nestedDescriptor != null) {
- // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz
- // is the
- // name we should record.
- int innerClassIndex =
- nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
- kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1));
- }
- },
- appView,
- namingLens,
- null);
+ nestedDescriptorBox::set, appView, namingLens, null);
+ if (nestedDescriptorBox.isSet()) {
+ if (nestedClassRewritten) {
+ // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz
+ // is the name we should record.
+ String nestedDescriptor = nestedDescriptorBox.get();
+ int innerClassIndex = nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
+ kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1));
+ } else {
+ kmClass.visitNestedClass(nestedClass.getOriginalName());
+ }
+ }
+ rewritten |= nestedClassRewritten;
}
// Rewrite sealed sub classes.
for (KotlinTypeReference sealedSubClass : sealedSubClasses) {
rewritten |=
sealedSubClass.toRenamedBinaryNameOrDefault(
- sealedDescriptor -> {
- if (sealedDescriptor != null) {
+ sealedName -> {
+ if (sealedName != null) {
kmClass.visitSealedSubclass(
- sealedDescriptor.replace(
+ sealedName.replace(
DescriptorUtils.INNER_CLASS_SEPARATOR,
DescriptorUtils.JAVA_PACKAGE_SEPARATOR));
}
@@ -409,7 +411,7 @@
declarationContainerInfo.trace(definitionSupplier);
forEachApply(typeParameters, param -> param::trace, definitionSupplier);
forEachApply(superTypes, type -> type::trace, definitionSupplier);
- forEachApply(sealedSubClasses, sealed -> sealed::trace, definitionSupplier);
+ forEachApply(sealedSubClasses, sealedClass -> sealedClass::trace, definitionSupplier);
forEachApply(nestedClasses, nested -> nested::trace, definitionSupplier);
localDelegatedProperties.trace(definitionSupplier);
// TODO(b/154347404): trace enum entries.
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
index e6a249c..5001c40 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -106,7 +106,8 @@
KmFunction kmFunction, DexItemFactory factory) {
String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction);
if (lambdaClassOriginName != null) {
- return KotlinTypeReference.fromBinaryName(lambdaClassOriginName, factory);
+ return KotlinTypeReference.fromBinaryName(
+ lambdaClassOriginName, factory, lambdaClassOriginName);
}
return null;
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index 0ff0070..fb6575c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -182,6 +182,13 @@
writeMetadataFieldInfo);
clazz.setAnnotations(clazz.annotations().rewrite(anno -> anno == oldMeta ? newMeta : anno));
} catch (Throwable t) {
+ assert appView.checkForTesting(
+ () -> {
+ throw appView
+ .options()
+ .reporter
+ .fatalError(KotlinMetadataDiagnostic.unexpectedErrorWhenRewriting(clazz.type, t));
+ });
appView
.options()
.reporter
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
index 7088c7f..0545b20 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
@@ -40,7 +40,7 @@
DexItemFactory factory) {
ImmutableList.Builder<KotlinTypeReference> builder = ImmutableList.builder();
for (String partClassName : kmMultiFileClassFacade.getPartClassNames()) {
- builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory));
+ builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory, partClassName));
}
return new KotlinMultiFileClassFacadeInfo(builder.build(), packageName, metadataVersion);
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index c166103..8cea528 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -24,28 +24,33 @@
class KotlinTypeReference implements EnqueuerMetadataTraceable {
private final DexType known;
- private final String unknown;
+ private final String originalName;
- private KotlinTypeReference(DexType known) {
+ private KotlinTypeReference(String originalName, DexType known) {
+ this.originalName = originalName;
this.known = known;
- this.unknown = null;
assert known != null;
}
- private KotlinTypeReference(String unknown) {
+ private KotlinTypeReference(String originalName) {
this.known = null;
- this.unknown = unknown;
- assert unknown != null;
+ this.originalName = originalName;
+ assert originalName != null;
}
public DexType getKnown() {
return known;
}
- static KotlinTypeReference fromBinaryName(String binaryName, DexItemFactory factory) {
+ public String getOriginalName() {
+ return originalName;
+ }
+
+ static KotlinTypeReference fromBinaryName(
+ String binaryName, DexItemFactory factory, String originalName) {
if (DescriptorUtils.isValidBinaryName(binaryName)) {
return fromDescriptor(
- DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, binaryName);
+ DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, originalName);
}
return new KotlinTypeReference(binaryName);
}
@@ -55,12 +60,12 @@
}
static KotlinTypeReference fromDescriptor(
- String descriptor, DexItemFactory factory, String unknownValue) {
+ String descriptor, DexItemFactory factory, String originalName) {
if (DescriptorUtils.isDescriptor(descriptor)) {
DexType type = factory.createType(descriptor);
- return new KotlinTypeReference(type);
+ return new KotlinTypeReference(originalName, type);
}
- return new KotlinTypeReference(unknownValue);
+ return new KotlinTypeReference(originalName);
}
boolean toRenamedDescriptorOrDefault(
@@ -68,11 +73,10 @@
AppView<?> appView,
NamingLens namingLens,
String defaultValue) {
- if (unknown != null) {
- rewrittenConsumer.accept(unknown);
+ if (known == null) {
+ rewrittenConsumer.accept(originalName);
return false;
}
- assert known != null;
DexType rewrittenType = toRewrittenTypeOrNull(appView, known);
if (rewrittenType == null) {
rewrittenConsumer.accept(defaultValue);
@@ -85,7 +89,7 @@
String toKotlinClassifier(boolean isLocalOrAnonymous) {
if (known == null) {
- return unknown;
+ return originalName;
}
return getKotlinLocalOrAnonymousNameFromDescriptor(
known.toDescriptorString(), isLocalOrAnonymous);
@@ -96,9 +100,9 @@
AppView<?> appView,
NamingLens namingLens,
String defaultValue) {
- if (unknown != null) {
+ if (known == null) {
// Unknown values are always on the input form, so we can just return it.
- rewrittenConsumer.accept(unknown);
+ rewrittenConsumer.accept(originalName);
return false;
}
return toRenamedDescriptorOrDefault(
@@ -136,7 +140,7 @@
@Override
public String toString() {
- return known != null ? known.descriptor.toString() : unknown;
+ return known != null ? known.descriptor.toString() : originalName;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index e53f285..ca54e1b 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -93,6 +93,10 @@
registerClassAsUsed(clazz.type, descriptor);
}
}
+ appView
+ .appInfo()
+ .getMissingClasses()
+ .forEach(missingClass -> registerClassAsUsed(missingClass, missingClass.getDescriptor()));
timing.end();
timing.begin("rename-classes");
diff --git a/src/main/java/com/android/tools/r8/naming/MapVersion.java b/src/main/java/com/android/tools/r8/naming/MapVersion.java
index 7069351..9c9c8d3 100644
--- a/src/main/java/com/android/tools/r8/naming/MapVersion.java
+++ b/src/main/java/com/android/tools/r8/naming/MapVersion.java
@@ -6,10 +6,11 @@
import com.android.tools.r8.utils.structural.Ordered;
public enum MapVersion implements Ordered<MapVersion> {
- MapVersionNone("none"),
- MapVersionExperimental("experimental");
+ MAP_VERSION_NONE("none"),
+ MAP_VERSION_1_0("1.0"),
+ MAP_VERSION_EXPERIMENTAL("experimental");
- public static final MapVersion STABLE = MapVersionNone;
+ public static final MapVersion STABLE = MAP_VERSION_1_0;
private final String name;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index f1e483f..52b63e0 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -90,7 +90,7 @@
private int lineNo = 0;
private int lineOffset = 0;
private String line;
- private MapVersion version = MapVersion.MapVersionNone;
+ private MapVersion version = MapVersion.MAP_VERSION_NONE;
private int peekCodePoint() {
return lineOffset < line.length() ? line.codePointAt(lineOffset) : '\n';
@@ -271,13 +271,13 @@
info -> {
MapVersionMappingInformation generatorInfo = info.asMetaInfMappingInformation();
if (generatorInfo != null) {
- if (generatorInfo.getMapVersion().equals(MapVersion.MapVersionExperimental)) {
+ if (generatorInfo.getMapVersion().equals(MapVersion.MAP_VERSION_EXPERIMENTAL)) {
// A mapping file that is marked "experimental" will be treated as an unversioned
// file if the compiler/tool is not explicitly running with experimental support.
version =
allowExperimentalMapping
- ? MapVersion.MapVersionExperimental
- : MapVersion.MapVersionNone;
+ ? MapVersion.MAP_VERSION_EXPERIMENTAL
+ : MapVersion.MAP_VERSION_NONE;
} else {
version = generatorInfo.getMapVersion();
}
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index 8ac5e71..2d36290 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -104,7 +104,7 @@
builder.append("# common_typos_disable" + "\n");
// Emit the R8 specific map-file version.
MapVersion mapVersion = options.getMapFileVersion();
- if (mapVersion.isGreaterThan(MapVersion.MapVersionNone)) {
+ if (mapVersion.isGreaterThan(MapVersion.MAP_VERSION_NONE)) {
builder
.append("# ")
.append(new MapVersionMappingInformation(mapVersion).serialize())
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
index 0c49e28..d26d9a8 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
@@ -12,7 +12,7 @@
public class CompilerSynthesizedMappingInformation extends MappingInformation {
- public static final MapVersion SUPPORTED_VERSION = MapVersion.MapVersionExperimental;
+ public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_1_0;
public static final String ID = "com.android.tools.r8.synthesized";
public static class Builder {
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 13455ba..dbec312 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
@@ -80,10 +80,7 @@
WorkList<DexProgramClass> worklist = WorkList.newIdentityWorkList(clazz);
while (worklist.hasNext()) {
DexProgramClass current = worklist.next();
- immediateSubtypingInfo.forEachImmediateSuperClassMatching(
- current,
- (supertype, superclass) -> superclass != null && superclass.isProgramClass(),
- (supertype, superclass) -> worklist.addIfNotSeen(superclass.asProgramClass()));
+ immediateSubtypingInfo.forEachImmediateProgramSuperClass(current, worklist::addIfNotSeen);
worklist.addIfNotSeen(immediateSubtypingInfo.getSubclasses(current));
}
return worklist.getSeenSet();
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 9a478bd..36dae85 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
@@ -137,12 +137,11 @@
unoptimizableInterfaceMethods.computeIfAbsent(clazz, ignoreKey(Sets::newIdentityHashSet));
// Add the unoptimizable interface methods from the parent interfaces.
- immediateSubtypingInfo.forEachImmediateSuperClassMatching(
+ immediateSubtypingInfo.forEachImmediateProgramSuperClass(
clazz,
- (supertype, superclass) -> superclass != null && superclass.isProgramClass(),
- (supertype, superclass) ->
+ superclass ->
unoptimizableInterfaceMethodsForClass.addAll(
- unoptimizableInterfaceMethods.get(superclass.asProgramClass())));
+ unoptimizableInterfaceMethods.get(superclass)));
// Propagate the unoptimizable interface methods of this interface to all immediate
// (non-interface) subclasses.
@@ -221,12 +220,9 @@
unoptimizableMethods.computeIfAbsent(clazz, ignoreKey(DexMethodSignatureSet::create));
// Add the unoptimizable methods from the parent classes.
- immediateSubtypingInfo.forEachImmediateSuperClassMatching(
+ immediateSubtypingInfo.forEachImmediateProgramSuperClass(
clazz,
- (supertype, superclass) -> superclass != null && superclass.isProgramClass(),
- (supertype, superclass) ->
- unoptimizableMethodsForClass.addAll(
- unoptimizableMethods.get(superclass.asProgramClass())));
+ superclass -> unoptimizableMethodsForClass.addAll(unoptimizableMethods.get(superclass)));
// Disable argument propagation for the unoptimizable methods of this class.
clazz.forEachProgramVirtualMethod(
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 99a0bac..69cbb7b 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
@@ -82,12 +82,11 @@
DexProgramClass interfaceDefinition) {
// Join the state for all parent interfaces into a fresh state created for this interface.
MethodStateCollectionBySignature interfaceState = MethodStateCollectionBySignature.create();
- immediateSubtypingInfo.forEachImmediateSuperClassMatching(
+ immediateSubtypingInfo.forEachImmediateProgramSuperClass(
interfaceDefinition,
- (supertype, superclass) -> superclass != null && superclass.isProgramClass(),
- (supertype, superclass) -> {
+ superclass -> {
MethodStateCollectionBySignature implementedInterfaceState =
- methodStatesToPropagate.get(superclass.asProgramClass());
+ methodStatesToPropagate.get(superclass);
assert implementedInterfaceState != null;
interfaceState.addMethodStates(appView, implementedInterfaceState);
});
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
index 14c58f8..771a718 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
@@ -46,10 +46,8 @@
PropagationState(DexProgramClass clazz) {
// Join the argument information from each of the super types.
- immediateSubtypingInfo.forEachImmediateSuperClassMatching(
- clazz,
- (supertype, superclass) -> superclass != null && superclass.isProgramClass(),
- (supertype, superclass) -> addParentState(clazz, superclass.asProgramClass()));
+ immediateSubtypingInfo.forEachImmediateProgramSuperClass(
+ clazz, superclass -> addParentState(clazz, superclass));
}
// TODO(b/190154391): This currently copies the state of the superclass into its immediate
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 6621857..8e34c3f 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -274,16 +274,25 @@
}
// Always repackage outer classes first, if any.
- InnerClassAttribute innerClassAttribute = classToRepackage.getInnerClassAttributeForThisClass();
DexProgramClass outerClass = null;
- if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
- outerClass = asProgramClassOrNull(appView.definitionFor(innerClassAttribute.getOuter()));
- if (outerClass != null) {
- if (pkg.contains(outerClass)) {
- processClass(outerClass, pkg, newPackageDescriptor, mappings);
- } else {
- outerClass = null;
- }
+ if (classToRepackage.hasEnclosingMethodAttribute()) {
+ DexType enclosingClass = classToRepackage.getEnclosingMethodAttribute().getEnclosingClass();
+ if (enclosingClass != null) {
+ outerClass = asProgramClassOrNull(appView.definitionFor(enclosingClass));
+ }
+ }
+ if (outerClass == null) {
+ InnerClassAttribute innerClassAttribute =
+ classToRepackage.getInnerClassAttributeForThisClass();
+ if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
+ outerClass = asProgramClassOrNull(appView.definitionFor(innerClassAttribute.getOuter()));
+ }
+ }
+ if (outerClass != null) {
+ if (pkg.contains(outerClass)) {
+ processClass(outerClass, pkg, newPackageDescriptor, mappings);
+ } else {
+ outerClass = null;
}
}
mappings.put(
@@ -318,13 +327,13 @@
public static class DefaultRepackagingConfiguration implements RepackagingConfiguration {
- private final AppView<?> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory dexItemFactory;
private final InternalOptions options;
private final ProguardConfiguration proguardConfiguration;
private final MinificationPackageNamingStrategy packageMinificationStrategy;
- public DefaultRepackagingConfiguration(AppView<?> appView) {
+ public DefaultRepackagingConfiguration(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
this.options = appView.options();
@@ -342,7 +351,7 @@
return newPackageDescriptor;
} else if (packageObfuscationMode.isMinification()) {
assert !proguardConfiguration.hasApplyMappingFile();
- // Always keep top-level classes since there packages can never be minified.
+ // Always keep top-level classes since their packages can never be minified.
if (pkg.getPackageDescriptor().equals("")
|| proguardConfiguration.getKeepPackageNamesPatterns().matches(pkg)
|| mayHavePinnedPackagePrivateOrProtectedItem(pkg)) {
@@ -383,15 +392,21 @@
private boolean mayHavePinnedPackagePrivateOrProtectedItem(ProgramPackage pkg) {
// Go through all package classes and members to see if there is a pinned package-private
- // item, in which case we cannot move it because there may be a reflective access to it.
+ // item, in which case we cannot move it because there could be an access to it from outside
+ // the program, which would be rewritten with -applymapping.
for (DexProgramClass clazz : pkg.classesInPackage()) {
if (clazz.getAccessFlags().isPackagePrivateOrProtected()
- && appView.getKeepInfo().getClassInfo(clazz).isPinned(options)) {
+ && !appView.getKeepInfo().getClassInfo(clazz).isShrinkingAllowed(options)) {
return true;
}
for (DexEncodedMember<?, ?> member : clazz.members()) {
+ // Skip the class initializer. Even if it is kept, it cannot be invoked, and thus we don't
+ // need any special handling to make sure it is always accessible to callers from tests.
+ if (member.isDexEncodedMethod() && member.asDexEncodedMethod().isClassInitializer()) {
+ continue;
+ }
if (member.getAccessFlags().isPackagePrivateOrProtected()
- && appView.getKeepInfo().getMemberInfo(member, clazz).isPinned(options)) {
+ && !appView.getKeepInfo().getMemberInfo(member, clazz).isShrinkingAllowed(options)) {
return true;
}
}
@@ -427,17 +442,19 @@
}
// Ensure that the generated name is unique.
DexType finalRepackagedDexType = repackagedDexType;
- for (int i = 1; isRepackageTypeUsed(finalRepackagedDexType, mappings, appView); i++) {
+ for (int i = 1; isRepackageTypeUsed(finalRepackagedDexType, mappings); i++) {
finalRepackagedDexType = repackagedDexType.addSuffix(i + "", dexItemFactory);
}
return finalRepackagedDexType;
}
- }
- private static boolean isRepackageTypeUsed(
- DexType type, BiMap<DexType, DexType> mappings, AppView<?> appView) {
- return mappings.inverse().containsKey(type)
- || (appView.hasLiveness() && appView.withLiveness().appInfo().wasPruned(type));
+ private boolean isRepackageTypeUsed(DexType type, BiMap<DexType, DexType> mappings) {
+ if (mappings.inverse().containsKey(type)) {
+ return true;
+ }
+ return appView.appInfo().wasPruned(type)
+ || appView.appInfo().getMissingClasses().contains(type);
+ }
}
/** Testing only. */
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
index 27247d4..2e7b6b5 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -116,13 +116,22 @@
MemberResolutionResult<?, ?> resolutionResult, boolean isInvoke) {
if (!resolutionResult.isSuccessfulMemberResolutionResult()) {
// To preserve errors in the original program, we need to look at the failure dependencies.
- // For example, if this method accesses in a package-private method in another package, and we
- // move the two methods to the same package, then the invoke would no longer fail with an
+ // For example, if this member accesses a package-private method in another package, and we
+ // move the two members to the same package, then the invoke would no longer fail with an
// IllegalAccessError.
- if (isInvoke) {
- // TODO(b/150589374): Only add this if we are in the minification mode of repackaging.
- node.addNeighbor(missingTypeNode);
+
+ // For fields and methods that cannot be found the chance of recovering by repackaging is
+ // pretty slim thus we allow for repackaging the callers.
+ if (resolutionResult.isFieldResolutionResult()) {
+ assert resolutionResult.asFieldResolutionResult().isFailedResolution();
+ return;
}
+ MethodResolutionResult methodResult = resolutionResult.asMethodResolutionResult();
+ if (methodResult.isClassNotFoundResult()
+ || methodResult.isNoSuchMethodErrorResult(context.getContextClass(), appInfo)) {
+ return;
+ }
+ node.addNeighbor(missingTypeNode);
return;
}
@@ -161,9 +170,6 @@
DexClass clazz = appInfo.definitionFor(type);
if (clazz != null) {
consumer.accept(clazz);
- } else {
- // The missing type reference can be package private and we cannot repackage.
- node.addNeighbor(missingTypeNode);
}
}
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 aef58b7..be31b16 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -986,11 +986,6 @@
if (!keepInfo.getInfo(clazz).isRepackagingAllowed(clazz, options())) {
return false;
}
- for (DexType superType : clazz.allImmediateSupertypes()) {
- if (definitionFor(superType) == null) {
- return false;
- }
- }
return clazz
.traverseProgramMembers(
member -> {
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
index 3d76d73..bfc3ae7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.shaking;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
@@ -22,7 +22,6 @@
import com.android.tools.r8.utils.Visibility;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.function.Function;
public class ClassInitFieldSynthesizer {
@@ -93,7 +92,7 @@
null,
deprecated,
DexEncodedField.D8_R8_SYNTHESIZED,
- getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+ minApiLevelIfEnabledOrUnknown(appView));
clazz.appendStaticField(encodedClinitField);
}
lensBuilder.map(type, encodedClinitField.getReference());
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index 5ffc72b..1dd5360 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -31,6 +31,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.function.Predicate;
public class MissingClasses {
@@ -56,6 +57,10 @@
.build();
}
+ public void forEach(Consumer<DexType> missingClassConsumer) {
+ missingClasses.forEach(missingClassConsumer);
+ }
+
public boolean contains(DexType type) {
return missingClasses.contains(type);
}
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 0a49379..27d25bb 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT;
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
import com.android.tools.r8.errors.Unreachable;
@@ -1451,8 +1450,8 @@
code,
true,
method.hasClassFileVersion() ? method.getClassFileVersion() : null,
- getApiLevelIfEnabledForNewMember(appView, method::getApiReferenceLevelForDefinition),
- getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+ method.getApiLevelForDefinition(),
+ method.getApiLevelForDefinition());
bridge.setLibraryMethodOverride(method.isLibraryMethodOverride());
if (method.accessFlags.isPromotedToPublic()) {
// The bridge is now the public method serving the role of the original method, and should
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 eb97f48..a86e143 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -508,16 +508,31 @@
DexProgramClass context,
AppView<?> appView,
Consumer<SyntheticProgramClassBuilder> fn) {
- // Obtain the outer synthesizing context in the case the context itself is synthetic.
- // This is to ensure a flat input-type -> synthetic-item mapping.
- SynthesizingContext outerContext =
- context.isProgramClass()
- ? getSynthesizingContext(context.asProgramClass(), appView)
- : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass());
+ SynthesizingContext outerContext = internalGetOuterContext(context, appView);
DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
return internalCreateClass(kind, fn, outerContext, type, appView.dexItemFactory());
}
+ public DexProgramClass getExistingFixedClass(
+ SyntheticKind kind, DexClass context, AppView<?> appView) {
+ assert kind.isFixedSuffixSynthetic;
+ SynthesizingContext outerContext = internalGetOuterContext(context, appView);
+ DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
+ DexClass clazz = appView.definitionFor(type);
+ assert clazz != null;
+ assert isSyntheticClass(type);
+ assert clazz.isProgramClass();
+ return clazz.asProgramClass();
+ }
+
+ // Obtain the outer synthesizing context in the case the context itself is synthetic.
+ // This is to ensure a flat input-type -> synthetic-item mapping.
+ private SynthesizingContext internalGetOuterContext(DexClass context, AppView<?> appView) {
+ return context.isProgramClass()
+ ? getSynthesizingContext(context.asProgramClass(), appView)
+ : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass());
+ }
+
/**
* Ensure that a fixed synthetic class exists.
*
@@ -530,12 +545,7 @@
Consumer<SyntheticProgramClassBuilder> fn,
Consumer<DexProgramClass> onCreationConsumer) {
assert kind.isFixedSuffixSynthetic;
- // Obtain the outer synthesizing context in the case the context itself is synthetic.
- // This is to ensure a flat input-type -> synthetic-item mapping.
- SynthesizingContext outerContext =
- context.isProgramClass()
- ? getSynthesizingContext(context.asProgramClass(), appView)
- : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass());
+ SynthesizingContext outerContext = internalGetOuterContext(context, appView);
DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
// Fast path is that the synthetic is already present. If so it must be a program class.
DexClass clazz = appView.definitionFor(type);
@@ -678,12 +688,8 @@
Consumer<SyntheticMethodBuilder> buildMethodCallback,
Consumer<T> newMethodCallback) {
MethodCollection methodCollection = clazz.getMethodCollection();
- DexEncodedMethod methodDefinition = methodCollection.getMethod(methodReference);
- if (methodDefinition != null) {
- return methodDefinition;
- }
synchronized (methodCollection) {
- methodDefinition = methodCollection.getMethod(methodReference);
+ DexEncodedMethod methodDefinition = methodCollection.getMethod(methodReference);
if (methodDefinition != null) {
return methodDefinition;
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
index adc3f40..196af3b 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -56,7 +56,7 @@
public SyntheticMethodBuilder setName(DexString name) {
assert name != null;
- assert this.name == null;
+ assert this.name == null || this.name == name;
this.name = name;
return this;
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 1e4082b..e127d6c 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.utils.structural.Ordered;
import java.util.Arrays;
import java.util.List;
@@ -75,6 +76,12 @@
return DexVersion.getDexVersion(this);
}
+ public static AndroidApiLevel minApiLevelIfEnabledOrUnknown(AppView<?> appView) {
+ return appView.options().apiModelingOptions().enableApiCallerIdentification
+ ? appView.options().minApiLevel
+ : UNKNOWN;
+ }
+
public static List<AndroidApiLevel> getAndroidApiLevelsSorted() {
return Arrays.asList(AndroidApiLevel.values());
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 9272066..96c4a2b 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -4,32 +4,10 @@
package com.android.tools.r8.utils;
-import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
-import java.util.function.Function;
public class AndroidApiLevelUtils {
- // Static api-level indicating that the api level is min-api.
- public static final AndroidApiLevel MIN_API_LEVEL = null;
-
- public static AndroidApiLevel getApiLevelIfEnabledForNewMember(
- AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) {
- AndroidApiLevel apiLevelIfEnabled = getApiLevelIfEnabled(appView, getter);
- if (apiLevelIfEnabled == appView.options().minApiLevel) {
- return MIN_API_LEVEL;
- }
- return apiLevelIfEnabled;
- }
-
- public static AndroidApiLevel getApiLevelIfEnabled(
- AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) {
- if (!appView.options().apiModelingOptions().enableApiCallerIdentification) {
- return AndroidApiLevel.UNKNOWN;
- }
- return getter.apply(appView.options().minApiLevel);
- }
-
public static OptionalBool isApiSafeForInlining(
ProgramMethod caller, ProgramMethod inlinee, InternalOptions options) {
if (!options.apiModelingOptions().enableApiCallerIdentification) {
@@ -41,8 +19,7 @@
return OptionalBool.of(
caller
.getDefinition()
- .getApiReferenceLevel(options.minApiLevel)
- .isGreaterThanOrEqualTo(
- inlinee.getDefinition().getApiReferenceLevelForCode(options.minApiLevel)));
+ .getApiLevel()
+ .isGreaterThanOrEqualTo(inlinee.getDefinition().getApiLevelForCode()));
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index d58387f..b1a2757 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -75,7 +75,11 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
+import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.util.CheckClassAdapter;
/**
* Collection of program files needed for processing.
@@ -762,6 +766,30 @@
return extractor.getDescriptor();
}
+ public void validateInputs() {
+ for (ProgramResourceProvider programResourceProvider : getProgramResourceProviders()) {
+ try {
+ for (ProgramResource programResource : programResourceProvider.getProgramResources()) {
+ try {
+ Kind kind = programResource.getKind();
+ if (kind == Kind.DEX) {
+ continue;
+ }
+ byte[] bytes = programResource.getBytes();
+ ClassReader classReader = new ClassReader(bytes);
+ classReader.accept(
+ new CheckClassAdapter(Opcodes.ASM9, new ClassNode(), true) {},
+ ClassReader.EXPAND_FRAMES);
+ } catch (Throwable e) {
+ throw new CompilationError("Failed validating " + programResource.getOrigin(), e);
+ }
+ }
+ } catch (ResourceException e) {
+ throw new CompilationError("Resource exception in validation", e);
+ }
+ }
+ }
+
/**
* Builder interface for constructing an AndroidApp.
*/
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 c0c5504..5ee21c1 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1210,7 +1210,7 @@
System.getProperty("com.android.tools.r8.noCfMarkerForDesugaredCode") != null;
}
- public static class CallSiteOptimizationOptions {
+ public class CallSiteOptimizationOptions {
// Each time we see an invoke with more dispatch targets than the threshold, we stop call site
// propagation for all these dispatch targets. The motivation for this is that it is expensive
@@ -1223,7 +1223,7 @@
private boolean enableExperimentalArgumentPropagation = false;
private boolean enableTypePropagation = true;
- private void disableOptimization() {
+ public void disableOptimization() {
enableConstantPropagation = false;
enableTypePropagation = false;
}
@@ -1232,18 +1232,14 @@
enableTypePropagation = false;
}
- // TODO(b/69963623): Remove this once enabled.
- @VisibleForTesting
- public static void enableConstantPropagationForTesting(InternalOptions options) {
- assert !options.callSiteOptimizationOptions().isConstantPropagationEnabled();
- options.callSiteOptimizationOptions().enableConstantPropagation = true;
- }
-
public int getMaxNumberOfDispatchTargetsBeforeAbandoning() {
return maxNumberOfDispatchTargetsBeforeAbandoning;
}
public boolean isEnabled() {
+ if (!isOptimizing()) {
+ return false;
+ }
return enableConstantPropagation || enableTypePropagation;
}
@@ -1264,12 +1260,19 @@
enableConstantPropagation = true;
}
- public void setEnableExperimentalArgumentPropagation() {
- assert !isExperimentalArgumentPropagationEnabled();
- enableExperimentalArgumentPropagation = true;
+ public void setEnableExperimentalArgumentPropagation(
+ boolean enableExperimentalArgumentPropagation) {
+ this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
}
}
+ // TODO(b/69963623): Remove this once enabled.
+ @VisibleForTesting
+ public static void enableConstantArgumentPropagationForTesting(InternalOptions options) {
+ assert !options.callSiteOptimizationOptions().isConstantPropagationEnabled();
+ options.callSiteOptimizationOptions().enableConstantPropagation = true;
+ }
+
public class HorizontalClassMergerOptions {
// TODO(b/138781768): Set enable to true when this bug is resolved.
@@ -1571,6 +1574,7 @@
public boolean disableMappingToOriginalProgramVerification = false;
public boolean allowInvalidCfAccessFlags =
System.getProperty("com.android.tools.r8.allowInvalidCfAccessFlags") != null;
+ public boolean verifyInputs = System.getProperty("com.android.tools.r8.verifyInputs") != null;
// TODO(b/177333791): Set to true
public boolean checkForNotExpandingMainDexTracingResult = false;
public Set<String> allowedUnusedDontWarnPatterns = new HashSet<>();
@@ -1640,7 +1644,7 @@
public MapVersion getMapFileVersion() {
return testing.enableExperimentalMapFileVersion
- ? MapVersion.MapVersionExperimental
+ ? MapVersion.MAP_VERSION_EXPERIMENTAL
: MapVersion.STABLE;
}
diff --git a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
index d8e0196..848c566 100644
--- a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
+++ b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
@@ -116,8 +116,12 @@
containsString(
"java.lang.NoClassDefFoundError: "
+ "Failed resolution of: Ljava/util/concurrent/Flow$Subscriber;"),
- // Art 10+.
- containsString("java.lang.ClassNotFoundException: MySubscriber")));
+ // Art 10.
+ containsString("java.lang.ClassNotFoundException: MySubscriber"),
+ // Art 11+.
+ containsString(
+ "java.lang.ClassNotFoundException: "
+ + "java.util.concurrent.SubmissionPublisher")));
} else {
if (parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
// java.util.concurrent.Flow$Subscriber not present in JDK8.
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index bcd4fea..f58f1fd 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -95,15 +95,17 @@
private static final String ART_TESTS_NATIVE_LIBRARY_DIR = "tests/2017-10-04/art/lib64";
private static final String ART_LEGACY_TESTS_NATIVE_LIBRARY_DIR = "tests/2016-12-19/art/lib64";
- private static final RuntimeSet LEGACY_RUNTIME = TestCondition.runtimes(
- DexVm.Version.V4_0_4,
- DexVm.Version.V4_4_4,
- DexVm.Version.V5_1_1,
- DexVm.Version.V6_0_1,
- DexVm.Version.V7_0_0,
- DexVm.Version.V8_1_0,
- DexVm.Version.V9_0_0,
- DexVm.Version.V10_0_0);
+ private static final RuntimeSet LEGACY_RUNTIME =
+ TestCondition.runtimes(
+ DexVm.Version.V4_0_4,
+ DexVm.Version.V4_4_4,
+ DexVm.Version.V5_1_1,
+ DexVm.Version.V6_0_1,
+ DexVm.Version.V7_0_0,
+ DexVm.Version.V8_1_0,
+ DexVm.Version.V9_0_0,
+ DexVm.Version.V10_0_0,
+ DexVm.Version.V12_0_0);
// Input jar for jctf tests.
private static final String JCTF_COMMON_JAR = "build/libs/jctfCommon.jar";
@@ -185,6 +187,18 @@
.put(
"134-reg-promotion",
TestCondition.match(TestCondition.runtimes(DexVm.Version.V10_0_0)))
+ // TODO(b/197078742): Triage - test OOMs.
+ .put(
+ "134-reg-promotion",
+ TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0)))
+ // TODO(b/197078746): Triage - fails with "java.lang.NoSuchMethodException:
+ // org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]"
+ .put("098-ddmc", TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0)))
+ // TODO(b/197079442): Triage - fails with "java.lang.NoSuchMethodException:
+ // org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]"
+ .put(
+ "145-alloc-tracking-stress",
+ TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0)))
.build();
// Tests that are flaky with the Art version we currently use.
@@ -488,115 +502,134 @@
static {
ImmutableMap.Builder<DexVm.Version, List<String>> builder = ImmutableMap.builder();
builder
- .put(DexVm.Version.V10_0_0, ImmutableList.of(
- // TODO(b/144975341): Triage, Verif error.
- "518-null-array-get",
- // TODO(b/144975341): Triage, Linking error.
- "457-regs",
- "543-env-long-ref",
- "454-get-vreg"
- ))
- .put(DexVm.Version.V9_0_0, ImmutableList.of(
- // TODO(120400625): Triage.
- "454-get-vreg",
- // TODO(120402198): Triage.
- "457-regs",
- // TODO(120401674): Triage.
- "543-env-long-ref",
- // TODO(120261858) Triage.
- "518-null-array-get"
- ))
- .put(DexVm.Version.V8_1_0, ImmutableList.of(
- // TODO(119938529): Triage.
- "709-checker-varhandles",
- "454-get-vreg",
- "457-regs"
- ))
- .put(DexVm.Version.V7_0_0, ImmutableList.of(
- // Addition of checks for super-class-initialization cause this to abort on non-ToT art.
- "008-exceptions",
+ .put(
+ DexVm.Version.V12_0_0,
+ ImmutableList.of("454-get-vreg", "457-regs", "543-env-long-ref", "518-null-array-get"))
+ .put(
+ DexVm.Version.V10_0_0,
+ ImmutableList.of(
+ // TODO(b/144975341): Triage, Verif error.
+ "518-null-array-get",
+ // TODO(b/144975341): Triage, Linking error.
+ "457-regs",
+ "543-env-long-ref",
+ "454-get-vreg"))
+ .put(
+ DexVm.Version.V9_0_0,
+ ImmutableList.of(
+ // TODO(120400625): Triage.
+ "454-get-vreg",
+ // TODO(120402198): Triage.
+ "457-regs",
+ // TODO(120401674): Triage.
+ "543-env-long-ref",
+ // TODO(120261858) Triage.
+ "518-null-array-get"))
+ .put(
+ DexVm.Version.V8_1_0,
+ ImmutableList.of(
+ // TODO(119938529): Triage.
+ "709-checker-varhandles", "454-get-vreg", "457-regs"))
+ .put(
+ DexVm.Version.V7_0_0,
+ ImmutableList.of(
+ // Addition of checks for super-class-initialization cause this to abort on non-ToT
+ // art.
+ "008-exceptions",
- // Generally fails on non-R8/D8 running.
- "156-register-dex-file-multi-loader",
- "412-new-array",
- "610-arraycopy",
- "625-checker-licm-regressions"))
- .put(DexVm.Version.V6_0_1, ImmutableList.of(
- // Addition of checks for super-class-initialization cause this to abort on non-ToT art.
- "008-exceptions",
+ // Generally fails on non-R8/D8 running.
+ "156-register-dex-file-multi-loader",
+ "412-new-array",
+ "610-arraycopy",
+ "625-checker-licm-regressions"))
+ .put(
+ DexVm.Version.V6_0_1,
+ ImmutableList.of(
+ // Addition of checks for super-class-initialization cause this to abort on non-ToT
+ // art.
+ "008-exceptions",
- // Generally fails on non-R8/D8 running.
- "004-checker-UnsafeTest18",
- "005-annotations",
- "008-exceptions",
- "082-inline-execute",
- "099-vmdebug",
- "156-register-dex-file-multi-loader",
- "412-new-array",
- "580-checker-round",
- "594-invoke-super",
- "625-checker-licm-regressions",
- "626-const-class-linking"))
- .put(DexVm.Version.V5_1_1, ImmutableList.of(
- // Addition of checks for super-class-initialization cause this to abort on non-ToT art.
- "008-exceptions",
+ // Generally fails on non-R8/D8 running.
+ "004-checker-UnsafeTest18",
+ "005-annotations",
+ "008-exceptions",
+ "082-inline-execute",
+ "099-vmdebug",
+ "156-register-dex-file-multi-loader",
+ "412-new-array",
+ "580-checker-round",
+ "594-invoke-super",
+ "625-checker-licm-regressions",
+ "626-const-class-linking"))
+ .put(
+ DexVm.Version.V5_1_1,
+ ImmutableList.of(
+ // Addition of checks for super-class-initialization cause this to abort on non-ToT
+ // art.
+ "008-exceptions",
- // Generally fails on non R8/D8 running.
- "004-checker-UnsafeTest18",
- "004-NativeAllocations",
- "005-annotations",
- "008-exceptions",
- "082-inline-execute",
- "099-vmdebug",
- "143-string-value",
- "156-register-dex-file-multi-loader",
- "536-checker-intrinsic-optimization",
- "552-invoke-non-existent-super",
- "580-checker-round",
- "580-checker-string-fact-intrinsics",
- "594-invoke-super",
- "605-new-string-from-bytes",
- "626-const-class-linking"))
- .put(DexVm.Version.V4_4_4, ImmutableList.of(
- // Addition of checks for super-class-initialization cause this to abort on non-ToT art.
- "008-exceptions",
+ // Generally fails on non R8/D8 running.
+ "004-checker-UnsafeTest18",
+ "004-NativeAllocations",
+ "005-annotations",
+ "008-exceptions",
+ "082-inline-execute",
+ "099-vmdebug",
+ "143-string-value",
+ "156-register-dex-file-multi-loader",
+ "536-checker-intrinsic-optimization",
+ "552-invoke-non-existent-super",
+ "580-checker-round",
+ "580-checker-string-fact-intrinsics",
+ "594-invoke-super",
+ "605-new-string-from-bytes",
+ "626-const-class-linking"))
+ .put(
+ DexVm.Version.V4_4_4,
+ ImmutableList.of(
+ // Addition of checks for super-class-initialization cause this to abort on non-ToT
+ // art.
+ "008-exceptions",
- // Generally fails on non R8/D8 running.
- "004-checker-UnsafeTest18",
- "004-NativeAllocations",
- "005-annotations",
- "008-exceptions",
- "082-inline-execute",
- "099-vmdebug",
- "143-string-value",
- "156-register-dex-file-multi-loader",
- "536-checker-intrinsic-optimization",
- "552-invoke-non-existent-super",
- "580-checker-round",
- "580-checker-string-fact-intrinsics",
- "594-invoke-super",
- "605-new-string-from-bytes",
- "626-const-class-linking"))
- .put(DexVm.Version.V4_0_4, ImmutableList.of(
- // Addition of checks for super-class-initialization cause this to abort on non-ToT art.
- "008-exceptions",
+ // Generally fails on non R8/D8 running.
+ "004-checker-UnsafeTest18",
+ "004-NativeAllocations",
+ "005-annotations",
+ "008-exceptions",
+ "082-inline-execute",
+ "099-vmdebug",
+ "143-string-value",
+ "156-register-dex-file-multi-loader",
+ "536-checker-intrinsic-optimization",
+ "552-invoke-non-existent-super",
+ "580-checker-round",
+ "580-checker-string-fact-intrinsics",
+ "594-invoke-super",
+ "605-new-string-from-bytes",
+ "626-const-class-linking"))
+ .put(
+ DexVm.Version.V4_0_4,
+ ImmutableList.of(
+ // Addition of checks for super-class-initialization cause this to abort on non-ToT
+ // art.
+ "008-exceptions",
- // Generally fails on non R8/D8 running.
- "004-checker-UnsafeTest18",
- "004-NativeAllocations",
- "005-annotations",
- "008-exceptions",
- "082-inline-execute",
- "099-vmdebug",
- "143-string-value",
- "156-register-dex-file-multi-loader",
- "536-checker-intrinsic-optimization",
- "552-invoke-non-existent-super",
- "580-checker-round",
- "580-checker-string-fact-intrinsics",
- "594-invoke-super",
- "605-new-string-from-bytes",
- "626-const-class-linking"));
+ // Generally fails on non R8/D8 running.
+ "004-checker-UnsafeTest18",
+ "004-NativeAllocations",
+ "005-annotations",
+ "008-exceptions",
+ "082-inline-execute",
+ "099-vmdebug",
+ "143-string-value",
+ "156-register-dex-file-multi-loader",
+ "536-checker-intrinsic-optimization",
+ "552-invoke-non-existent-super",
+ "580-checker-round",
+ "580-checker-string-fact-intrinsics",
+ "594-invoke-super",
+ "605-new-string-from-bytes",
+ "626-const-class-linking"));
expectedToFailRunWithArtVersion = builder.build();
}
@@ -2050,6 +2083,10 @@
System.out.println("Running on 10.0.0 is disabled, see b/144966342");
continue;
}
+ if (vm.getVersion() == DexVm.Version.V12_0_0) {
+ System.out.println("Running on 12.0.0 is disabled, see b/197078995");
+ continue;
+ }
vms.add(new DexRuntime(vm));
}
}
diff --git a/src/test/java/com/android/tools/r8/TestCondition.java b/src/test/java/com/android/tools/r8/TestCondition.java
index d72ba77..07fff0e 100644
--- a/src/test/java/com/android/tools/r8/TestCondition.java
+++ b/src/test/java/com/android/tools/r8/TestCondition.java
@@ -25,6 +25,7 @@
ART_V8_1_0,
ART_V9_0_0,
ART_V10_0_0,
+ ART_V12_0_0,
ART_DEFAULT,
JAVA;
@@ -49,6 +50,8 @@
return ART_V9_0_0;
case V10_0_0:
return ART_V10_0_0;
+ case V12_0_0:
+ return ART_V12_0_0;
case DEFAULT:
return ART_DEFAULT;
default:
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index 23e2e5c..90d4f75 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -145,6 +145,14 @@
return assertFailure();
}
+ public RR assertFailureWithErrorThatMatchesIf(boolean condition, Matcher<String> matcher) {
+ if (condition) {
+ assertStderrMatches(matcher);
+ return assertFailure();
+ }
+ return self();
+ }
+
public RR assertFailureWithOutput(String expected) {
assertStdoutMatches(is(expected));
return assertFailure();
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index a1bdeb8..a38852e 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -256,7 +256,9 @@
ART_9_0_0_TARGET(Version.V9_0_0, Kind.TARGET),
ART_9_0_0_HOST(Version.V9_0_0, Kind.HOST),
ART_10_0_0_TARGET(Version.V10_0_0, Kind.TARGET),
- ART_10_0_0_HOST(Version.V10_0_0, Kind.HOST);
+ ART_10_0_0_HOST(Version.V10_0_0, Kind.HOST),
+ ART_12_0_0_TARGET(Version.V12_0_0, Kind.TARGET),
+ ART_12_0_0_HOST(Version.V12_0_0, Kind.HOST);
private static final ImmutableMap<String, DexVm> SHORT_NAME_MAP =
Arrays.stream(DexVm.values()).collect(ImmutableMap.toImmutableMap(
@@ -271,7 +273,8 @@
V8_1_0("8.1.0"),
DEFAULT("default"),
V9_0_0("9.0.0"),
- V10_0_0("10.0.0");
+ V10_0_0("10.0.0"),
+ V12_0_0("12.0.0");
Version(String shortName) {
this.shortName = shortName;
@@ -289,6 +292,10 @@
return this == last();
}
+ public boolean isEqualTo(Version other) {
+ return compareTo(other) == 0;
+ }
+
public boolean isNewerThan(Version other) {
return compareTo(other) > 0;
}
@@ -321,7 +328,7 @@
}
public static Version last() {
- return V10_0_0;
+ return V12_0_0;
}
static {
@@ -358,10 +365,22 @@
return SHORT_NAME_MAP.get(version.shortName + "_" + Kind.HOST.toString());
}
+ public boolean isEqualTo(DexVm other) {
+ return version.isNewerThanOrEqual(other.version);
+ }
+
public boolean isNewerThan(DexVm other) {
return version.isNewerThan(other.version);
}
+ public boolean isNewerThanOrEqual(DexVm other) {
+ return version.isNewerThanOrEqual(other.version);
+ }
+
+ public boolean isOlderThan(DexVm other) {
+ return version.isOlderThan(other.version);
+ }
+
public boolean isOlderThanOrEqual(DexVm other) {
return version.isOlderThanOrEqual(other.version);
}
@@ -580,6 +599,7 @@
private static final Map<DexVm, String> ART_DIRS =
ImmutableMap.<DexVm, String>builder()
.put(DexVm.ART_DEFAULT, "art")
+ .put(DexVm.ART_12_0_0_HOST, "host/art-12.0.0-beta4")
.put(DexVm.ART_10_0_0_HOST, "art-10.0.0")
.put(DexVm.ART_9_0_0_HOST, "art-9.0.0")
.put(DexVm.ART_8_1_0_HOST, "art-8.1.0")
@@ -587,10 +607,12 @@
.put(DexVm.ART_6_0_1_HOST, "art-6.0.1")
.put(DexVm.ART_5_1_1_HOST, "art-5.1.1")
.put(DexVm.ART_4_4_4_HOST, "dalvik")
- .put(DexVm.ART_4_0_4_HOST, "dalvik-4.0.4").build();
+ .put(DexVm.ART_4_0_4_HOST, "dalvik-4.0.4")
+ .build();
private static final Map<DexVm, String> ART_BINARY_VERSIONS =
ImmutableMap.<DexVm, String>builder()
.put(DexVm.ART_DEFAULT, "bin/art")
+ .put(DexVm.ART_12_0_0_HOST, "bin/art")
.put(DexVm.ART_10_0_0_HOST, "bin/art")
.put(DexVm.ART_9_0_0_HOST, "bin/art")
.put(DexVm.ART_8_1_0_HOST, "bin/art")
@@ -598,16 +620,19 @@
.put(DexVm.ART_6_0_1_HOST, "bin/art")
.put(DexVm.ART_5_1_1_HOST, "bin/art")
.put(DexVm.ART_4_4_4_HOST, "bin/dalvik")
- .put(DexVm.ART_4_0_4_HOST, "bin/dalvik").build();
+ .put(DexVm.ART_4_0_4_HOST, "bin/dalvik")
+ .build();
private static final Map<DexVm, String> ART_BINARY_VERSIONS_X64 =
ImmutableMap.<DexVm, String>builder()
.put(DexVm.ART_DEFAULT, "bin/art")
+ .put(DexVm.ART_12_0_0_HOST, "bin/art")
.put(DexVm.ART_10_0_0_HOST, "bin/art")
.put(DexVm.ART_9_0_0_HOST, "bin/art")
.put(DexVm.ART_8_1_0_HOST, "bin/art")
.put(DexVm.ART_7_0_0_HOST, "bin/art")
- .put(DexVm.ART_6_0_1_HOST, "bin/art").build();
+ .put(DexVm.ART_6_0_1_HOST, "bin/art")
+ .build();
private static final List<String> DALVIK_BOOT_LIBS =
ImmutableList.of(
@@ -627,6 +652,7 @@
ImmutableMap.Builder<DexVm, List<String>> builder = ImmutableMap.builder();
builder
.put(DexVm.ART_DEFAULT, ART_BOOT_LIBS)
+ .put(DexVm.ART_12_0_0_HOST, ART_BOOT_LIBS)
.put(DexVm.ART_10_0_0_HOST, ART_BOOT_LIBS)
.put(DexVm.ART_9_0_0_HOST, ART_BOOT_LIBS)
.put(DexVm.ART_8_1_0_HOST, ART_BOOT_LIBS)
@@ -644,6 +670,7 @@
ImmutableMap.Builder<DexVm, String> builder = ImmutableMap.builder();
builder
.put(DexVm.ART_DEFAULT, "angler")
+ .put(DexVm.ART_12_0_0_HOST, "redfin")
.put(DexVm.ART_10_0_0_HOST, "coral")
.put(DexVm.ART_9_0_0_HOST, "marlin")
.put(DexVm.ART_8_1_0_HOST, "marlin")
@@ -1002,6 +1029,8 @@
switch (dexVm.version) {
case DEFAULT:
return AndroidApiLevel.O;
+ case V12_0_0:
+ return AndroidApiLevel.S;
case V10_0_0:
return AndroidApiLevel.Q;
case V9_0_0:
@@ -1898,7 +1927,8 @@
public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm vm) throws IOException {
// TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?)
Assume.assumeTrue(ToolHelper.isDex2OatSupported());
- Assume.assumeFalse("b/144975341", vm.version == DexVm.Version.V10_0_0);
+ Assume.assumeFalse(
+ "b/144975341", vm.version == DexVm.Version.V10_0_0 || vm.version == DexVm.Version.V12_0_0);
if (vm.isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
// Run default dex2oat for tests on dalvik runtimes.
vm = DexVm.ART_DEFAULT;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
index 04337ec..c87f2cc 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
@@ -7,7 +7,7 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack;
import static com.android.tools.r8.utils.AndroidApiLevel.LATEST;
import static com.android.tools.r8.utils.AndroidApiLevel.R;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -56,7 +56,7 @@
addTracedApiReferenceLevelCallBack(
(method, apiLevel) -> {
if (Reference.methodFromMethod(main).equals(method)) {
- assertEquals(R, apiLevel);
+ assertTrue(apiLevel.isGreaterThanOrEqualTo(R));
}
}))
.compile();
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
index 71b6637..9fffa07 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
@@ -6,6 +6,8 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
@@ -88,6 +90,23 @@
.assertSuccessWithOutputLines(EXPECTED);
}
+ @Test()
+ public void testR8InputVerification() throws Exception {
+ try {
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(getMainWithChangedMaxStackHeight())
+ .enableInliningAnnotations()
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.testing.verifyInputs = true)
+ .compile();
+ } catch (CompilationFailedException e) {
+ assertTrue(e.getCause().getMessage().contains("Insufficient maximum stack size"));
+ return;
+ }
+ fail("Should always throw");
+ }
+
public byte[] getMainWithChangedMaxStackHeight() throws Exception {
return transformer(Main.class).setMaxStackHeight(MethodPredicate.onName("main"), 1).transform();
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
index c39b7b5..d1cedfc 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.naming.retrace.StackTrace;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
import org.junit.Before;
import org.junit.Test;
@@ -55,21 +54,7 @@
.inspectStackTrace(
(stackTrace, codeInspector) -> {
assertThat(codeInspector.clazz(A.class), isPresent());
- StackTrace expectedStackTraceWithMergedConstructor =
- StackTrace.builder()
- .add(expectedStackTrace)
- .add(
- 2,
- StackTraceLine.builder()
- .setClassName(A.class.getTypeName())
- // TODO(b/124483578): The synthetic method should not be part of the
- // retraced stack trace.
- .setMethodName("$r8$init$synthetic")
- .setFileName(getClass().getSimpleName() + ".java")
- .setLineNumber(0)
- .build())
- .build();
- assertThat(stackTrace, isSame(expectedStackTraceWithMergedConstructor));
+ assertThat(stackTrace, isSame(expectedStackTrace));
assertThat(codeInspector.clazz(B.class), not(isPresent()));
});
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java
index 9b5b87d..cb0b232 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java
@@ -13,9 +13,7 @@
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.classmerging.horizontal.MergedConstructorStackTraceTest.A;
import com.android.tools.r8.naming.retrace.StackTrace;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
import org.junit.Before;
import org.junit.Test;
@@ -63,16 +61,6 @@
// constructors should retrace to the set of lines from each of the
// individual source constructors.
.map(1, stackTraceLine -> stackTraceLine.builderOf().setLineNumber(0).build())
- // TODO(b/124483578): The synthetic method should not be part of the retraced
- // stack trace.
- .add(
- 2,
- StackTraceLine.builder()
- .setClassName(A.class.getTypeName())
- .setMethodName("$r8$init$synthetic")
- .setFileName(getClass().getSimpleName() + ".java")
- .setLineNumber(0)
- .build())
.build();
assertThat(stackTrace, isSame(expectedStackTraceWithMergedConstructor));
assertThat(codeInspector.clazz(B.class), not(isPresent()));
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
index 0375885..12edd71 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.naming.retrace.StackTrace;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
import org.junit.Before;
import org.junit.Test;
@@ -54,20 +53,7 @@
(stackTrace, codeInspector) -> {
assertThat(codeInspector.clazz(Program.A.class), isPresent());
assertThat(codeInspector.clazz(Program.B.class), isAbsent());
- StackTrace expectedStackTraceWithMergedMethod =
- StackTrace.builder()
- .add(expectedStackTrace)
- .add(
- 1,
- StackTraceLine.builder()
- .setClassName(Program.A.class.getTypeName())
- .setMethodName("foo$bridge")
- .setFileName("Program.java")
- .setFileName(getClass().getSimpleName() + ".java")
- .setLineNumber(stackTrace.get(1).lineNumber)
- .build())
- .build();
- assertThat(stackTrace, isSame(expectedStackTraceWithMergedMethod));
+ assertThat(stackTrace, isSame(expectedStackTrace));
});
}
diff --git a/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java
index bdcfd8a..59853ee 100644
--- a/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar;
+import static org.hamcrest.CoreMatchers.containsString;
+
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -38,7 +40,12 @@
.compile()
.addRunClasspathClasses(MissingInterface.class)
.run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatThrows(AbstractMethodError.class);
+ // We allow for renaming if the class is missing
+ .assertFailureWithErrorThatMatchesIf(
+ parameters.getDexRuntimeVersion().isDalvik(),
+ containsString(descriptor(MissingInterface.class) + "' is not accessible"))
+ .assertFailureWithErrorThatThrowsIf(
+ !parameters.getDexRuntimeVersion().isDalvik(), IllegalAccessError.class);
}
interface MissingInterface {
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
index 37aa606..81038d6 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
@@ -4,17 +4,18 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class ByteBackportJava9Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -31,7 +32,8 @@
public ByteBackportJava9Test(TestParameters parameters) {
super(parameters, Byte.class, TEST_JAR, "backport.ByteBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to ByteBackportTest.
+
+ // Byte.compareUnsigned added in API 31.
+ registerTarget(AndroidApiLevel.S, 16);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
index 309b319..7b80e96 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
@@ -4,9 +4,12 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
@@ -14,8 +17,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public class ListBackportJava10Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -40,5 +41,8 @@
ignoreInvokes("get");
ignoreInvokes("set");
ignoreInvokes("size");
+
+ // List.copyOf added in API 31.
+ registerTarget(AndroidApiLevel.S, 3);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
index 0d55065..ddf502b 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -44,13 +44,16 @@
ignoreInvokes("get");
ignoreInvokes("set");
ignoreInvokes("size");
+
+ // List.of added in API 30.
+ registerTarget(AndroidApiLevel.R, 18);
}
@Test
public void desugaringApiLevelR() throws Exception {
- // TODO(154759404): This test should start to fail when testing on an Android R VM.
- if (parameters.getRuntime().isDex()
- && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) {
+ // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+ // This has now been checked with S, when R testing is added check and remove this.
+ if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.Q)) {
testForD8()
.setMinApi(AndroidApiLevel.R)
.addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
index e54d7d8..11008cc 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
@@ -4,9 +4,12 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
@@ -14,8 +17,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public class MapBackportJava10Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -40,5 +41,8 @@
ignoreInvokes("get");
ignoreInvokes("put");
ignoreInvokes("size");
+
+ // Map.copyOf added in API 31.
+ registerTarget(AndroidApiLevel.S, 4);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
index 27cb824..73ffa29 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
@@ -44,13 +44,16 @@
ignoreInvokes("get");
ignoreInvokes("put");
ignoreInvokes("size");
+
+ // Map.entry, Map.of and Map.ofEntries added in API 30.
+ registerTarget(AndroidApiLevel.R, 29);
}
@Test
public void desugaringApiLevelR() throws Exception {
- // TODO(154759404): This test should start to fail when testing on an Android R VM.
- if (parameters.getRuntime().isDex()
- && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) {
+ // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+ // This has now been checked with S, when R testing is added check and remove this.
+ if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) {
testForD8()
.setMinApi(AndroidApiLevel.R)
.addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
index 387697e..2f70fc2 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.runner.RunWith;
@@ -31,7 +32,9 @@
public MathBackportJava9Test(TestParameters parameters) {
super(parameters, Math.class, TEST_JAR, "backport.MathBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to MathBackportTest.
+
+ // Math.floorDiv, Math.floorMod, Math.multiplyExact, Math.multiplyFull and Math.multiplyHigh
+ // added in API 31.
+ registerTarget(AndroidApiLevel.S, 27);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
index 09aef1e..527d2c0 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Objects;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,16 +35,20 @@
private static final String TEST_CLASS = "backport.ObjectsBackportJava9Main";
public ObjectsBackportJava9Test(TestParameters parameters) {
- super(parameters, Short.class, TEST_JAR, TEST_CLASS);
+ super(parameters, Objects.class, TEST_JAR, TEST_CLASS);
// Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
// an actual API level, migrate these tests to ObjectsBackportTest.
+
+ // Objects.checkFromIndexSize, Objects.checkFromToIndex, Objects.checkIndex,
+ // Objects.requireNonNullElse and Objects.requireNonNullElseGet added in API 30.
+ registerTarget(AndroidApiLevel.R, 28);
}
@Test
public void desugaringApiLevelR() throws Exception {
- // TODO(154759404): This test should start to fail when testing on an Android R VM.
- if (parameters.getRuntime().isDex()
- && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) {
+ // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+ // This has now been checked with S, when R testing is added chck and remove this.
+ if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) {
testForD8()
.setMinApi(AndroidApiLevel.R)
.addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
index 5c08b8f..2a17cb2 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
@@ -4,9 +4,12 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
@@ -14,8 +17,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public class SetBackportJava10Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -39,5 +40,10 @@
ignoreInvokes("add");
ignoreInvokes("contains");
ignoreInvokes("size");
+
+ // Set.of added in API 30
+ registerTarget(AndroidApiLevel.R, 1);
+ // Set.copyOf added in API 31
+ registerTarget(AndroidApiLevel.S, 5);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
index 408b203..652cde0 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
@@ -43,13 +43,16 @@
ignoreInvokes("add");
ignoreInvokes("contains");
ignoreInvokes("size");
+
+ // Set.of added in API 30.
+ registerTarget(AndroidApiLevel.R, 21);
}
@Test
public void desugaringApiLevelR() throws Exception {
- // TODO(154759404): This test should start to fail when testing on an Android R VM.
- if (parameters.getRuntime().isDex()
- && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) {
+ // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+ // This has now been checked with S, when R testing is added check and remove this.
+ if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) {
testForD8()
.setMinApi(AndroidApiLevel.R)
.addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
index beffd8a..d1d3c95 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
@@ -4,17 +4,18 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class ShortBackportJava9Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -31,7 +32,8 @@
public ShortBackportJava9Test(TestParameters parameters) {
super(parameters, Short.class, TEST_JAR, "backport.ShortBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to ShortBackportTest.
+
+ // Short.compareUnsigned added in API 31.
+ registerTarget(AndroidApiLevel.S, 16);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java
index 61cf95d..1ebfe97 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java
@@ -5,6 +5,8 @@
package com.android.tools.r8.desugar.backports;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import org.junit.runner.RunWith;
@@ -24,18 +26,29 @@
public SparseArrayBackportTest(TestParameters parameters) throws IOException {
super(
parameters,
- SparseArrayBackportTest.getSparseArray(),
+ SparseArrayBackportTest.getSparseArray(parameters),
ImmutableList.of(
- SparseArrayBackportTest.getTestRunner(), SparseArrayBackportTest.getSparseArray()));
+ SparseArrayBackportTest.getTestRunner(),
+ SparseArrayBackportTest.getSparseArray(parameters)));
// The constructor is used by the test and put has been available since API 1 and is the
// method set is rewritten to.
ignoreInvokes("<init>");
ignoreInvokes("put");
+
+ // android.util.SparseArray.set added in API 31.
+ registerTarget(AndroidApiLevel.S, 1);
}
- private static byte[] getSparseArray() throws IOException {
- return transformer(SparseArray.class).setClassDescriptor(SPARSE_ARRAY_DESCRIPTOR).transform();
+ private static byte[] getSparseArray(TestParameters parameters) throws IOException {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.S)) {
+ assert parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_12_0_0_HOST);
+ return transformer(SparseArrayAndroid12.class)
+ .setClassDescriptor(SPARSE_ARRAY_DESCRIPTOR)
+ .transform();
+ } else {
+ return transformer(SparseArray.class).setClassDescriptor(SPARSE_ARRAY_DESCRIPTOR).transform();
+ }
}
private static byte[] getTestRunner() throws IOException {
@@ -56,6 +69,17 @@
}
}
+ public static class SparseArrayAndroid12 {
+ public void set(int index, Object value) {
+ TestRunner.doAssertEquals(42, index);
+ TestRunner.doAssertEquals("Forty two", value);
+ }
+
+ public void put(int index, Object value) {
+ TestRunner.doFail("put should not be called");
+ }
+ }
+
public static class TestRunner extends MiniAssert {
public static void main(String[] args) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
index c8ddd5d..2d6b833 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
@@ -134,6 +135,10 @@
@Test
public void testTime() throws Exception {
+ if (parameters.getRuntime().asDex().getVm().isEqualTo(DexVm.ART_12_0_0_HOST)) {
+ // TODO(b/197078988): Many additional tests fails with Android 12.
+ return;
+ }
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
String verbosity = "2";
D8TestCompileResult compileResult =
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java
index cd2b968..363e539 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java
@@ -111,13 +111,6 @@
result.assertSuccessWithOutput(EXPECTED);
return;
}
- if (!unexpectedArtFailure() && !parameters.canUseDefaultAndStaticInterfaceMethods()) {
- assert false : "Dead code until future ART behavior change. See b/152199517";
- // Desugaring will insert a forwarding bridge which will hide the "invalid invoke" case.
- // Thus, a future ART runtime that does not have the invalid IAE for the private override
- // will end up calling the forward method to I.m.
- result.assertSuccessWithOutput(EXPECTED);
- }
// The expected behavior is IAE since the resolved method is private.
result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
return;
@@ -142,7 +135,8 @@
private boolean unexpectedArtFailure() {
return parameters.isDexRuntime()
- && parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_6_0_1_HOST);
+ && parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_6_0_1_HOST)
+ && parameters.getRuntime().asDex().getVm().isOlderThan(DexVm.ART_12_0_0_HOST);
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
index 92f5365..12869e2 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
@@ -116,7 +116,8 @@
if (isR8
&& parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1)) {
+ && parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1)
+ && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0)) {
// TODO(b/182255398): This should be EXPECTED.
result.assertSuccessWithOutput(EXPECTED_R8);
return;
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodReferencesTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodReferencesTest.java
new file mode 100644
index 0000000..7589f8a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodReferencesTest.java
@@ -0,0 +1,74 @@
+// Copyright (c) 2021, 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.desugaring.interfacemethods;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class InterfaceWithClinitAndNoStaticMethodReferencesTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("allocated A", "called A.m");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().withAllApiLevelsAlsoForCf().build();
+ }
+
+ public InterfaceWithClinitAndNoStaticMethodReferencesTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testReference() throws Exception {
+ testForDesugaring(parameters)
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(InterfaceWithClinitAndNoStaticMethodReferencesTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ static class A {
+
+ A() {
+ System.out.println("allocated A");
+ }
+
+ void m() {
+ System.out.println("called A.m");
+ }
+ }
+
+ interface I {
+
+ A a = new A();
+
+ static void f() {
+ System.out.println("unused");
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ I.a.m();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodsTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodsTest.java
new file mode 100644
index 0000000..414520f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodsTest.java
@@ -0,0 +1,70 @@
+// Copyright (c) 2021, 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.desugaring.interfacemethods;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class InterfaceWithClinitAndNoStaticMethodsTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("allocated A", "called A.m");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().withAllApiLevelsAlsoForCf().build();
+ }
+
+ public InterfaceWithClinitAndNoStaticMethodsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testReference() throws Exception {
+ testForDesugaring(parameters)
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(InterfaceWithClinitAndNoStaticMethodsTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ static class A {
+
+ A() {
+ System.out.println("allocated A");
+ }
+
+ void m() {
+ System.out.println("called A.m");
+ }
+ }
+
+ interface I {
+
+ A a = new A();
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ I.a.m();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java
index d53a470..9b42105 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java
@@ -45,14 +45,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(CallSiteOptimizationLibraryLambdaPropagationTest.class)
.addKeepMainRule(TestClass.class)
- .applyIf(
- enableExperimentalArgumentPropagation,
- builder ->
- builder.addOptionsModification(
- options ->
- options
- .callSiteOptimizationOptions()
- .setEnableExperimentalArgumentPropagation()))
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(
+ enableExperimentalArgumentPropagation))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java
index 2bf8f8d..ea88ead 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java
@@ -63,14 +63,12 @@
+ "Arg getArg2(); \npublic static "
+ CLASS_PREFIX
+ "Call getCaller(); \n}"))
- .applyIf(
- enableExperimentalArgumentPropagation,
- builder ->
- builder.addOptionsModification(
- options ->
- options
- .callSiteOptimizationOptions()
- .setEnableExperimentalArgumentPropagation()))
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(
+ enableExperimentalArgumentPropagation))
.enableNoVerticalClassMergingAnnotations()
.enableNoHorizontalClassMergingAnnotations()
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java
index 6d8e9d4..2771975 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java
@@ -38,14 +38,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(CallSiteOptimizationProgramLambdaPropagationTest.class)
.addKeepMainRule(TestClass.class)
- .applyIf(
- enableExperimentalArgumentPropagation,
- builder ->
- builder.addOptionsModification(
- options ->
- options
- .callSiteOptimizationOptions()
- .setEnableExperimentalArgumentPropagation()))
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(
+ enableExperimentalArgumentPropagation))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java
index d0d2d22..5edca84 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java
@@ -67,14 +67,12 @@
.addProgramClassFileData(getProgramClassFileData())
.addKeepMainRule(TestClass.class)
.addKeepMethodRules(methodFromMethod(TestClass.class.getDeclaredMethod("bar", int.class)))
- .applyIf(
- enableExperimentalArgumentPropagation,
- builder ->
- builder.addOptionsModification(
- options ->
- options
- .callSiteOptimizationOptions()
- .setEnableExperimentalArgumentPropagation()))
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(
+ enableExperimentalArgumentPropagation))
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java
index 4db8c2f..20827d8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java
@@ -38,14 +38,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(CallSiteOptimizationWithLambdaTargetTest.class)
.addKeepMainRule(TestClass.class)
- .applyIf(
- enableExperimentalArgumentPropagation,
- builder ->
- builder.addOptionsModification(
- options ->
- options
- .callSiteOptimizationOptions()
- .setEnableExperimentalArgumentPropagation()))
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(
+ enableExperimentalArgumentPropagation))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
index b579686..452e472 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
@@ -48,14 +48,12 @@
.addInnerClasses(KeptMethodTest.class)
.addKeepMainRule(MAIN)
.addKeepClassAndMembersRules(A.class)
- .applyIf(
- enableExperimentalArgumentPropagation,
- builder ->
- builder.addOptionsModification(
- options ->
- options
- .callSiteOptimizationOptions()
- .setEnableExperimentalArgumentPropagation()))
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(
+ enableExperimentalArgumentPropagation))
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
index ea7641f..2d6bec7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
@@ -63,14 +63,12 @@
.addOptionsModification(
o ->
o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
- .applyIf(
- enableExperimentalArgumentPropagation,
- builder ->
- builder.addOptionsModification(
- options ->
- options
- .callSiteOptimizationOptions()
- .setEnableExperimentalArgumentPropagation()))
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(
+ enableExperimentalArgumentPropagation))
.enableInliningAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
index 55daa59..e3fa7d7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -52,7 +52,7 @@
o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
})
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting)
+ .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null")
.inspect(this::inspect);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
index 9f25fdb..93594ff 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
@@ -16,7 +16,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -49,7 +49,7 @@
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
- .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting)
+ .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.addOptionsModification(
o -> {
// To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
index 3a00d96..096362a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -50,7 +50,7 @@
o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
})
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting)
+ .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null")
.inspect(this::inspect);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
index 5b3b309..e254dc6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -16,7 +16,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -53,7 +53,7 @@
o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
})
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting)
+ .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null", "null")
.inspect(this::inspect);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java b/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java
index 39acb1e..bde8237 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java
@@ -36,6 +36,16 @@
}
@Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(getProgramClassFileData())
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Foo", "Bar", "Expected NPE");
+ }
+
+ @Test
public void test() throws Exception {
testForR8(parameters.getBackend())
.addProgramClassFileData(getProgramClassFileData())
@@ -62,7 +72,7 @@
testNullArgumentMethodSubject, not(invokesMethodWithName("requireNonNullElse")));
})
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("Foo", "Bar");
+ .assertSuccessWithOutputLines("Foo", "Bar", "Expected NPE");
}
private byte[] getProgramClassFileData() throws IOException {
@@ -77,6 +87,12 @@
public static void main(String[] args) {
testNonNullArgument();
testNullArgument();
+ try {
+ testNullArgumentAndNullDefaultValue();
+ System.out.println("Unexpected");
+ } catch (NullPointerException e) {
+ System.out.println("Expected NPE");
+ }
}
@NeverInline
@@ -88,6 +104,11 @@
static void testNullArgument() {
System.out.println(Mock.requireNonNullElse(null, "Bar"));
}
+
+ @NeverInline
+ static void testNullArgumentAndNullDefaultValue() {
+ System.out.println(Mock.requireNonNullElse(null, null));
+ }
}
// References to this class are rewritten to java.util.Objects by transformation.
diff --git a/src/test/java/com/android/tools/r8/naming/MissingReferenceNamingClashTest.java b/src/test/java/com/android/tools/r8/naming/MissingReferenceNamingClashTest.java
new file mode 100644
index 0000000..1082d2e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MissingReferenceNamingClashTest.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2021, 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.naming;
+
+import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
+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.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/** This is a reproduction of b/196406764 */
+@RunWith(Parameterized.class)
+public class MissingReferenceNamingClashTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public MissingReferenceNamingClashTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // The references to Missing will be rewritten to a.a but the definition will not be present.
+ String newDescriptor = "La/a;";
+ testForR8(parameters.getBackend())
+ .addProgramClasses(A.class, Main.class)
+ .addProgramClassFileData(
+ transformer(Anno.class)
+ .replaceClassDescriptorInMembers(descriptor(Missing.class), newDescriptor)
+ .transform())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .addKeepClassAndMembersRules(Anno.class)
+ .addKeepClassRulesWithAllowObfuscation(A.class)
+ .addKeepRuntimeVisibleAnnotations()
+ .addDontWarn(descriptorToJavaType(newDescriptor))
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject aSubject = inspector.clazz(A.class);
+ assertThat(aSubject, isPresent());
+ assertEquals("La/b;", aSubject.getFinalDescriptor());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A::foo");
+ }
+
+ /* Will be missing on input */
+ public enum Missing {
+ FOO;
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface Anno {
+
+ /* Rewritten to a.a */ Missing missing();
+ }
+
+ public static class A {
+
+ public void foo() {
+ System.out.println("A::foo");
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ new A().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/PackageMinificationWithDontOptimizeTest.java b/src/test/java/com/android/tools/r8/naming/PackageMinificationWithDontOptimizeTest.java
new file mode 100644
index 0000000..45c9f14
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/PackageMinificationWithDontOptimizeTest.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2021, 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.naming;
+
+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.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.util.Properties;
+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 PackageMinificationWithDontOptimizeTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addDontOptimize()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject classSubject = inspector.clazz(TestClass.class);
+ assertThat(classSubject, isPresent());
+ assertEquals("a.a", classSubject.getFinalName());
+ });
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ TestClass.getProperty("abc");
+ TestClass.getProperty("def");
+ }
+ }
+
+ public static class TestClass {
+
+ private static final Properties properties = new Properties();
+
+ public static String getProperty(String key) {
+ return properties.getProperty(key);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java
index 1fbc7cf..7a4914a 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java
@@ -12,7 +12,6 @@
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.ImmutableList;
@@ -76,12 +75,6 @@
assertEquals(expectedActualStackTraceHeight(), actualStackTrace.size());
}
- @Override
- public void configure(R8TestBuilder<?> builder) {
- // Enable pruning of lambda synthetics in retrace.
- builder.enableExperimentalMapFileVersion();
- }
-
@Test
public void testSourceFileAndLineNumberTable() throws Exception {
runTest(ImmutableList.of("-keepattributes SourceFile,LineNumberTable"), this::checkIsSame);
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java
index b0a87ee..2cbb911 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java
@@ -48,7 +48,6 @@
@Override
public void configure(R8TestBuilder<?> builder) {
builder.enableInliningAnnotations();
- builder.enableExperimentalMapFileVersion();
}
@Test
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java
index 38ef3038..56f306c 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java
@@ -38,7 +38,6 @@
@Override
public void configure(R8TestBuilder<?> builder) {
builder.enableInliningAnnotations();
- builder.enableExperimentalMapFileVersion();
}
@Override
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
index 4e44d1f..9b246e1 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
@@ -44,7 +44,7 @@
options -> {
CallSiteOptimizationOptions callSiteOptimizationOptions =
options.callSiteOptimizationOptions();
- callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation();
+ callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(true);
callSiteOptimizationOptions.setEnableConstantPropagation();
})
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
index b0387b2..45cd552 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
@@ -44,7 +44,7 @@
options -> {
CallSiteOptimizationOptions callSiteOptimizationOptions =
options.callSiteOptimizationOptions();
- callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation();
+ callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(true);
callSiteOptimizationOptions.setEnableConstantPropagation();
})
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
index df0bfa6..2265ba0 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.repackage;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
-import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
@@ -52,10 +52,6 @@
.inspect(
inspector -> {
// Find the generated lambda class
- if (!parameters.isDexRuntime()) {
- assertThat(ClassWithLambda.class, isNotRepackaged(inspector));
- return;
- }
if (repackage) {
assertThat(ClassWithLambda.class, isRepackaged(inspector));
} else {
@@ -66,7 +62,8 @@
clazz -> {
if (clazz.isSynthesizedJavaLambdaClass()) {
assertThat(
- clazz.getFinalName(), containsString(Main.class.getPackage().getName()));
+ clazz.getFinalName(),
+ startsWith(repackage ? getRepackagePackage() : "a."));
}
});
})
@@ -74,7 +71,7 @@
.run(parameters.getRuntime(), Main.class);
}
- interface MissingInterface {
+ public interface MissingInterface {
void bar(int x);
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java
index 9dc8746..8a40226 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java
@@ -4,10 +4,10 @@
package com.android.tools.r8.repackage;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -25,16 +25,16 @@
@Test
public void testR8WithoutRepackaging() throws Exception {
- runTest(false).assertSuccessWithOutputLines(EXPECTED);
+ runTest(false);
}
@Test
public void testR8() throws Exception {
- runTest(true).assertSuccessWithOutputLines(EXPECTED);
+ runTest(true);
}
- private R8TestRunResult runTest(boolean repackage) throws Exception {
- return testForR8(parameters.getBackend())
+ private void runTest(boolean repackage) throws Exception {
+ testForR8(parameters.getBackend())
.addProgramClasses(ClassWithMissingReferenceInCode.class, Main.class)
.addKeepMainRule(Main.class)
.applyIf(repackage, this::configureRepackaging)
@@ -43,13 +43,20 @@
.enableInliningAnnotations()
.compile()
.inspect(
- inspector ->
- assertThat(ClassWithMissingReferenceInCode.class, isNotRepackaged(inspector)))
+ inspector -> {
+ if (repackage) {
+ assertThat(ClassWithMissingReferenceInCode.class, isRepackaged(inspector));
+ } else {
+ assertThat(
+ inspector.clazz(ClassWithMissingReferenceInCode.class), isPresentAndRenamed());
+ }
+ })
.addRunClasspathClasses(MissingReference.class)
- .run(parameters.getRuntime(), Main.class);
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
}
- static class MissingReference {
+ public static class MissingReference {
public static void doSomething() {
System.out.println("MissingReference::doSomething");
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java
index c853a99..e5ffadc 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.repackage;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -26,16 +27,16 @@
@Test
public void testR8WithoutRepackaging() throws Exception {
- runTest(false).assertSuccessWithOutputLines(EXPECTED);
+ runTest(false);
}
@Test
public void testR8() throws Exception {
- runTest(true).assertSuccessWithOutputLines(EXPECTED);
+ runTest(true);
}
- private R8TestRunResult runTest(boolean repackage) throws Exception {
- return testForR8(parameters.getBackend())
+ private void runTest(boolean repackage) throws Exception {
+ testForR8(parameters.getBackend())
.addProgramClasses(ClassImplementingMissingInterface.class, Main.class)
.addKeepMainRule(Main.class)
.applyIf(repackage, this::configureRepackaging)
@@ -46,13 +47,20 @@
.compile()
.inspect(
inspector -> {
- assertThat(ClassImplementingMissingInterface.class, isNotRepackaged(inspector));
+ if (repackage) {
+ assertThat(ClassImplementingMissingInterface.class, isRepackaged(inspector));
+ } else {
+ // The class is minified.
+ ClassSubject clazz = inspector.clazz(ClassImplementingMissingInterface.class);
+ assertThat(clazz, isPresentAndRenamed());
+ }
})
.addRunClasspathClasses(MissingInterface.class)
- .run(parameters.getRuntime(), Main.class);
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
}
- private interface MissingInterface {
+ public interface MissingInterface {
void bar();
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java
index 5880f86..af4995f 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java
@@ -4,11 +4,11 @@
package com.android.tools.r8.repackage;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,16 +32,16 @@
@Test
public void testR8WithoutRepackaging() throws Exception {
- runTest(false).assertSuccessWithOutputLines(EXPECTED);
+ runTest(false);
}
@Test
public void testR8() throws Exception {
- runTest(true).assertSuccessWithOutputLines(EXPECTED);
+ runTest(true);
}
- private R8TestRunResult runTest(boolean repackage) throws Exception {
- return testForR8(parameters.getBackend())
+ private void runTest(boolean repackage) throws Exception {
+ testForR8(parameters.getBackend())
.addProgramClasses(
ClassWithSuperCall.class,
ClassWithoutSuperCall.class,
@@ -56,14 +56,20 @@
.compile()
.inspect(
inspector -> {
- assertThat(ClassWithSuperCall.class, isNotRepackaged(inspector));
- assertThat(ClassWithoutSuperCall.class, isNotRepackaged(inspector));
+ if (repackage) {
+ assertThat(ClassWithSuperCall.class, isRepackaged(inspector));
+ assertThat(ClassWithoutSuperCall.class, isRepackaged(inspector));
+ } else {
+ assertThat(inspector.clazz(ClassWithSuperCall.class), isPresentAndRenamed());
+ assertThat(inspector.clazz(ClassWithoutSuperCall.class), isPresentAndRenamed());
+ }
})
.addRunClasspathClasses(MissingSuperType.class)
- .run(parameters.getRuntime(), Main.class);
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
}
- static class MissingSuperType {
+ public static class MissingSuperType {
public void foo() {
System.out.println("MissingSuperType::foo");
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java
new file mode 100644
index 0000000..2fc2cb0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java
@@ -0,0 +1,143 @@
+// Copyright (c) 2021, 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.repackage;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.R8CompatTestBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/* This is a reproduction of b/196406764 where a collision will appear when repackaging */
+@RunWith(Parameterized.class)
+public class RepackageMissingTypeCollisionTest extends RepackageTestBase {
+
+ public RepackageMissingTypeCollisionTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ super(flattenPackageHierarchyOrRepackageClasses, parameters);
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ String newMissingTypeName =
+ getRepackagePackage() + (isFlattenPackageHierarchy() ? ".a.a" : ".a");
+ String newMissingDescriptor = DescriptorUtils.javaTypeToDescriptor(newMissingTypeName);
+ String newATypeName = A.class.getPackage().getName() + ".a";
+ String newADescriptor = DescriptorUtils.javaTypeToDescriptor(newATypeName);
+ testForJvm()
+ .addProgramClassFileData(
+ transformer(A.class).setClassDescriptor(newADescriptor).transform(),
+ transformer(Anno.class)
+ .replaceClassDescriptorInMembers(descriptor(Missing.class), newMissingDescriptor)
+ .replaceClassDescriptorInAnnotationDefault(
+ descriptor(Missing.class), newMissingDescriptor)
+ .transform(),
+ transformer(Main.class)
+ .replaceClassDescriptorInMethodInstructions(descriptor(A.class), newADescriptor)
+ .replaceClassDescriptorInMethodInstructions(
+ descriptor(Missing.class), newMissingDescriptor)
+ .transform())
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(NoClassDefFoundError.class);
+ }
+
+ @Test
+ public void testRepackageMissingCollision() throws Exception {
+ testMissingReference(true)
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject clazz = inspector.clazz(getNewATypeName());
+ assertThat(clazz, isPresentAndRenamed());
+ assertEquals(
+ getRepackagePackage() + (isFlattenPackageHierarchy() ? ".a.b" : ".b"),
+ clazz.getFinalName());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(NoClassDefFoundError.class);
+ }
+
+ @Test
+ public void testNoRepackage() throws Exception {
+ testMissingReference(false)
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(NoClassDefFoundError.class);
+ }
+
+ private String getNewMissingTypeName() {
+ return getRepackagePackage() + (isFlattenPackageHierarchy() ? ".a.a" : ".a");
+ }
+
+ private String getNewATypeName() {
+ return A.class.getPackage().getName() + ".a";
+ }
+
+ private R8CompatTestBuilder testMissingReference(boolean repackage) throws Exception {
+ // The references to Missing will be rewritten to <repackage>.a but the definition will not be
+ // present.
+ String newMissingDescriptor = DescriptorUtils.javaTypeToDescriptor(getNewMissingTypeName());
+ String newADescriptor = DescriptorUtils.javaTypeToDescriptor(getNewATypeName());
+ return testForR8Compat(parameters.getBackend())
+ .addProgramClassFileData(
+ transformer(A.class).setClassDescriptor(newADescriptor).transform(),
+ transformer(Anno.class)
+ .replaceClassDescriptorInMembers(descriptor(Missing.class), newMissingDescriptor)
+ .replaceClassDescriptorInAnnotationDefault(
+ descriptor(Missing.class), newMissingDescriptor)
+ .transform(),
+ transformer(Main.class)
+ .replaceClassDescriptorInMethodInstructions(descriptor(A.class), newADescriptor)
+ .replaceClassDescriptorInMethodInstructions(
+ descriptor(Missing.class), newMissingDescriptor)
+ .transform())
+ .addKeepMainRule(Main.class)
+ .addKeepClassAndMembersRules(Anno.class)
+ .addKeepRuntimeVisibleAnnotations()
+ .applyIf(repackage, this::configureRepackaging)
+ .setMinApi(parameters.getApiLevel())
+ .addDontWarn(getNewMissingTypeName())
+ .addOptionsModification(internalOptions -> internalOptions.enableEnumUnboxing = false)
+ .addHorizontallyMergedClassesInspector(
+ HorizontallyMergedClassesInspector::assertNoClassesMerged);
+ }
+
+ /* Will be missing on input */
+ public enum Missing {
+ foo;
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface Anno {
+
+ /* Renamed to <repackage>.a */ Missing missing() default Missing.foo;
+ }
+
+ @Anno
+ public enum /* renamed to a */ A {
+ foo;
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ Anno annotation = A.class.getAnnotation(Anno.class);
+ System.out.println(annotation.missing());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
index f7aae45..252dcc5 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -66,7 +66,6 @@
public void testD8() throws Exception {
testForD8(parameters.getBackend())
.internalEnableMappingOutput()
- .enableExperimentalMapFileVersion()
.addInnerClasses(getClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
@@ -102,7 +101,6 @@
"Skip R8/CF for min-api > 1 (R8/CF does not desugar)",
parameters.isDexRuntime() || parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
testForR8(parameters.getBackend())
- .enableExperimentalMapFileVersion()
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addKeepPackageNamesRule(getClass().getPackage())
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index efa7b4e..e110f57 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -74,6 +74,7 @@
case V4_0_4:
case V4_4_4:
case V10_0_0:
+ case V12_0_0:
return StringUtils.joinLines("Hello!", "Goodbye!", "");
case V7_0_0:
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index fb2db95..ea7b6cc 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.utils.DescriptorUtils.getBinaryNameFromDescriptor;
import static com.android.tools.r8.utils.StringUtils.replaceAll;
import static org.objectweb.asm.Opcodes.ASM7;
+import static org.objectweb.asm.Opcodes.ASM9;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -740,6 +741,57 @@
});
}
+ public ClassFileTransformer replaceClassDescriptorInMembers(
+ String oldDescriptor, String newDescriptor) {
+ return addClassTransformer(
+ new ClassTransformer() {
+ @Override
+ public FieldVisitor visitField(
+ int access, String name, String descriptor, String signature, Object value) {
+ return super.visitField(
+ access,
+ name,
+ replaceAll(descriptor, oldDescriptor, newDescriptor),
+ signature,
+ value);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String descriptor, String signature, String[] exceptions) {
+ return super.visitMethod(
+ access,
+ name,
+ replaceAll(descriptor, oldDescriptor, newDescriptor),
+ signature,
+ exceptions);
+ }
+ });
+ }
+
+ public ClassFileTransformer replaceClassDescriptorInAnnotationDefault(
+ String oldDescriptor, String newDescriptor) {
+ return addMethodTransformer(
+ new MethodTransformer() {
+
+ @Override
+ public AnnotationVisitor visitAnnotationDefault() {
+ return new AnnotationVisitor(ASM9, super.visitAnnotationDefault()) {
+ @Override
+ public void visit(String name, Object value) {
+ super.visit(name, value);
+ }
+
+ @Override
+ public void visitEnum(String name, String descriptor, String value) {
+ super.visitEnum(
+ name, descriptor.equals(oldDescriptor) ? newDescriptor : descriptor, value);
+ }
+ };
+ }
+ });
+ }
+
public ClassFileTransformer replaceClassDescriptorInMethodInstructions(
String oldDescriptor, String newDescriptor) {
return addMethodTransformer(
diff --git a/tools/compiledump.py b/tools/compiledump.py
index 83bc2aa..e8070da 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -252,6 +252,19 @@
utils.download_file_from_cloud_storage(source, dest)
return dest
+
+def clean_config(file):
+ with open(file) as f:
+ lines = f.readlines()
+ with open(file, 'w') as f:
+ for line in lines:
+ if ('-injars' not in line and '-libraryjars' not in line and
+ '-print' not in line):
+ f.write(line)
+ else:
+ print('Removing from config line: \n%s' % line)
+
+
def prepare_wrapper(dist, temp, jdkhome):
wrapper_file = os.path.join(
utils.REPO_ROOT,
@@ -329,6 +342,10 @@
if compiler != 'd8' and dump.config_file():
if hasattr(args, 'config_file_consumer') and args.config_file_consumer:
args.config_file_consumer(dump.config_file())
+ else:
+ # If we get a dump from the wild we can't use -injars, -libraryjars or
+ # -print{mapping,usage}
+ clean_config(dump.config_file())
cmd.extend(['--pg-conf', dump.config_file()])
if dump.main_dex_rules_resource():
cmd.extend(['--main-dex-rules', dump.main_dex_rules_resource()])
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions
index 9cf0717..ff57695 100644
--- a/tools/linux/README.art-versions
+++ b/tools/linux/README.art-versions
@@ -41,6 +41,33 @@
repo init -u https://android.googlesource.com/platform/manifest -m aosp_master_manifest.xml
<continue with repo sync as above>
+
+art-12.0.0 (Android S)
+---------------------
+Build from branch sc-beta4-release.
+
+export BRANCH=sc-beta4-release
+mkdir ${BRANCH}
+cd ${BRANCH}
+repo init -u https://android.googlesource.com/platform/manifest -b ${BRANCH}
+repo sync -cq -j24
+source build/envsetup.sh
+lunch aosp_redfin-userdebug
+m -j48
+m -j48 build-art
+m -j48 test-art-host
+
+Collected into tools/linux/host/art-12.0.0-beta4. The "host" path element is checked
+by the script for running Art.
+
+ cd <r8 checkout>
+ scripts/update-host-art.sh \
+ --android-checkout /usr/local/ssd/android/${BRANCH} \
+ --art-dir host/art-12.0.0-beta4 \
+ --android-product redfin
+
+(cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-12.0.0-beta4)
+
art-10.0.0 (Android Q)
---------------------
Build from branch android-10.0.0_r14.
diff --git a/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1 b/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1
new file mode 100644
index 0000000..b95d909
--- /dev/null
+++ b/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1
@@ -0,0 +1 @@
+9b6d0b061669e0fb1b09ba92c3650d5c7bdc9e85
\ No newline at end of file
diff --git a/tools/test.py b/tools/test.py
index 9c35352..6553358 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -23,6 +23,7 @@
ALL_ART_VMS = [
"default",
+ "12.0.0",
"10.0.0",
"9.0.0",
"8.1.0",