Merge commit '4e73b4a3fab11eaa523953de084645744b8c2e05' into dev-release
diff --git a/.gitignore b/.gitignore
index 2e7f798..ceddaef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -266,8 +266,8 @@
tools/*/art-10.0.0.tar.gz
tools/*/host/art-12.0.0-beta4
tools/*/host/art-12.0.0-beta4.tar.gz
-tools/*/host/art-13-master
-tools/*/host/art-13-master.tar.gz
+tools/*/host/art-13-dev
+tools/*/host/art-13-dev.tar.gz
tools/*/art.tar.gz
tools/*/dalvik
tools/*/dalvik-4.0.4
diff --git a/README.md b/README.md
index 2d24142..1621acb 100644
--- a/README.md
+++ b/README.md
@@ -24,11 +24,11 @@
$ git clone https://r8.googlesource.com/r8
$ cd r8
- $ tools/gradle.py d8 r8
+ $ tools/gradle.py r8
The `tools/gradle.py` script will bootstrap using depot_tools to download
a version of gradle to use for building on the first run. This will produce
-two jar files: `build/libs/d8.jar` and `build/libs/r8.jar`.
+a jar file: `build/libs/r8.jar` which contains both R8 and D8.
## Running D8
@@ -45,11 +45,11 @@
Debug mode build:
- $ java -jar build/libs/d8.jar --output out input.jar
+ $ java -cp build/libs/r8.jar com.android.tools.r8.D8 --output out input.jar
Release mode build:
- $ java -jar build/libs/d8.jar --release --output out input.jar
+ $ java -cp build/libs/r8.jar com.android.tools.r8.D8 --release --output out input.jar
The full set of D8 options can be obtained by running the command line tool with
the `--help` option.
diff --git a/build.gradle b/build.gradle
index e5467f0..5f7b6d0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -369,7 +369,7 @@
"linux/art-9.0.0",
"linux/art-10.0.0",
"linux/host/art-12.0.0-beta4",
- "linux/host/art-13-master",
+ "linux/host/art-13-dev",
"linux/dalvik",
"linux/dalvik-4.0.4",
"${osString}/dx",
@@ -929,15 +929,6 @@
outputs.file "${buildDir}/libs/r8_no_manifest.jar"
}
-task D8(type: Jar) {
- dependsOn r8
- from zipTree(r8.outputs.files[0])
- archiveFileName = 'd8.jar'
- manifest {
- attributes 'Main-Class': 'com.android.tools.r8.D8'
- }
-}
-
def baseCompilerCommandLine(compiler, args = []) {
// Execute r8 commands against a stable r8 with dependencies.
// TODO(b/139725780): See if we can remove or lower the heap size (-Xmx8g).
diff --git a/src/library_desugar/java/android/os/Build.java b/src/library_desugar/java/android/os/Build.java
new file mode 100644
index 0000000..908c94c
--- /dev/null
+++ b/src/library_desugar/java/android/os/Build.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package android.os;
+
+public class Build {
+ public static class VERSION {
+ public static final int SDK_INT = 0;
+ }
+}
diff --git a/src/library_desugar/java/android/os/StrictMode.java b/src/library_desugar/java/android/os/StrictMode.java
new file mode 100644
index 0000000..5cd5ff1
--- /dev/null
+++ b/src/library_desugar/java/android/os/StrictMode.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package android.os;
+
+public class StrictMode {
+
+ public static ThreadPolicy getThreadPolicy() {
+ return null;
+ }
+
+ public static void setThreadPolicy(ThreadPolicy policy) {}
+
+ public static class ThreadPolicy {
+ public static class Builder {
+ public Builder(ThreadPolicy policy) {}
+
+ public Builder permitDiskReads() {
+ return null;
+ }
+
+ public ThreadPolicy build() {
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java b/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java
new file mode 100644
index 0000000..cf36b80
--- /dev/null
+++ b/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package desugar.sun.nio.fs;
+
+import java.nio.file.spi.FileSystemProvider;
+
+public class DesugarDefaultFileSystemProvider {
+
+ public static FileSystemProvider instance() {
+ return null;
+ }
+}
diff --git a/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileTypeDetector.java b/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileTypeDetector.java
new file mode 100644
index 0000000..916d6e0
--- /dev/null
+++ b/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileTypeDetector.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package desugar.sun.nio.fs;
+
+import java.nio.file.spi.FileTypeDetector;
+
+public class DesugarDefaultFileTypeDetector {
+ public static FileTypeDetector create() {
+ return null;
+ }
+}
diff --git a/src/library_desugar/java/j$/nio/file/Files.java b/src/library_desugar/java/j$/nio/file/Files.java
new file mode 100644
index 0000000..2825d24
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/Files.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package j$.nio.file;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public class Files {
+ public static String probeContentType(Path path) throws IOException {
+ return null;
+ }
+}
diff --git a/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
new file mode 100644
index 0000000..658c351
--- /dev/null
+++ b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package java.adapter;
+
+import android.os.Build.VERSION;
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
+import desugar.sun.nio.fs.DesugarDefaultFileSystemProvider;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.spi.FileSystemProvider;
+
+/**
+ * A hybrid file system provider adapter that delegates different implementations based on the
+ * runtime environment.
+ */
+public final class HybridFileSystemProvider {
+ private static final FileSystemProvider INSTANCE = getFileSystemProvider();
+ private static final FileSystem FILE_SYSTEM_INSTANCE =
+ INSTANCE.getFileSystem(URI.create("file:///"));
+
+ private static FileSystemProvider getFileSystemProvider() {
+ if (VERSION.SDK_INT >= 26) {
+ return FileSystems.getDefault().provider();
+ } else {
+ try {
+ // In headless, android.os is absent so the following line will throw.
+ // We cannot set the ThreadPolicy in headless and it is irrelevant.
+ // If we are not in headless, the class will be found and we can set the thread policy.
+ Class.forName("android.os.Build");
+ setThreadPolicy();
+ } catch (ClassNotFoundException ignored) {
+ // Headless mode.
+ }
+ return DesugarDefaultFileSystemProvider.instance();
+ }
+ }
+
+ private static void setThreadPolicy() {
+ // The references to the android.os methods need to be outlined.
+ // TODO(b/207004118): Fix the strict mode allowlisting.
+ ThreadPolicy threadPolicy = StrictMode.getThreadPolicy();
+ StrictMode.setThreadPolicy(new ThreadPolicy.Builder(threadPolicy).permitDiskReads().build());
+ }
+
+ private HybridFileSystemProvider() {}
+
+ /** Returns the platform's default file system provider. */
+ public static FileSystemProvider instance() {
+ return INSTANCE;
+ }
+
+ /** Returns the platform's default file system. */
+ public static FileSystem theFileSystem() {
+ return FILE_SYSTEM_INSTANCE;
+ }
+}
diff --git a/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
new file mode 100644
index 0000000..1caf2f1
--- /dev/null
+++ b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package java.adapter;
+
+import android.os.Build.VERSION;
+import desugar.sun.nio.fs.DesugarDefaultFileTypeDetector;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.spi.FileTypeDetector;
+
+/**
+ * A hybrid file type detector adapter that delegates different implementations based on the runtime
+ * environment.
+ */
+public final class HybridFileTypeDetector {
+ private HybridFileTypeDetector() {}
+
+ public static FileTypeDetector create() {
+ if (VERSION.SDK_INT >= 26) {
+ return new PlatformFileTypeDetector();
+ } else {
+ return DesugarDefaultFileTypeDetector.create();
+ }
+ }
+
+ static class PlatformFileTypeDetector extends java.nio.file.spi.FileTypeDetector {
+ @Override
+ public String probeContentType(Path path) throws IOException {
+ // Relies at runtime on java.nio.file.Files.
+ return j$.nio.file.Files.probeContentType(path);
+ }
+ }
+}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index c2cea80..6893b8f 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -6,20 +6,6 @@
"support_all_callbacks_from_library": true,
"common_flags": [
{
- "api_level_below_or_equal": 32,
- "rewrite_prefix": {
- "java.net.URLDecoder": "j$.net.URLDecoder",
- "java.net.URLEncoder": "j$.net.URLEncoder",
- "java.io.DesugarInputStream": "j$.io.DesugarInputStream"
- },
- "retarget_method_with_emulated_dispatch": {
- "long java.io.InputStream#transferTo(java.io.OutputStream)": "java.io.DesugarInputStream"
- },
- "amend_library_method": [
- "public long java.io.InputStream#transferTo(java.io.OutputStream)"
- ]
- },
- {
"api_level_below_or_equal": 30,
"rewrite_prefix": {
"java.time.": "j$.time.",
@@ -175,16 +161,6 @@
"java.util.OptionalInt": "java.util.OptionalConversions",
"java.util.OptionalLong": "java.util.OptionalConversions"
}
- },
- {
- "api_level_below_or_equal": 18,
- "rewrite_prefix": {
- "java.lang.DesugarCharacter": "j$.lang.DesugarCharacter",
- "java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
- },
- "retarget_method": {
- "boolean java.lang.Character#isBmpCodePoint(int)": "java.lang.DesugarCharacter"
- }
}
],
"program_flags": [
@@ -215,76 +191,32 @@
"long java.util.concurrent.atomic.AtomicLong#getAndUpdate(java.util.function.LongUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong",
"long java.util.concurrent.atomic.AtomicLong#updateAndGet(java.util.function.LongUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong"
}
- },
- {
- "api_level_below_or_equal": 19,
- "dont_retarget": [
- "android.support.multidex.MultiDexExtractor$ExtractedDex"
- ]
}
],
"library_flags": [
{
- "api_level_below_or_equal": 32,
- "rewrite_prefix": {
- "desugar.": "j$.desugar.",
- "libcore.": "j$.libcore.",
- "java.lang.Desugar": "j$.lang.Desugar",
- "java.lang.ref.Cleaner": "j$.lang.ref.Cleaner",
- "sun.security.action.": "j$.sun.security.action."
- }
- },
- {
"api_level_below_or_equal": 30,
+ "rewrite_prefix": {
+ "jdk.internal.": "j$.jdk.internal.",
+ "sun.security.action.": "j$.sun.security.action.",
+ "sun.misc.Desugar": "j$.sun.misc.Desugar"
+ },
"rewrite_derived_prefix": {
"java.time.": {
"j$.time.": "java.time."
}
- }
- },
- {
- "api_level_below_or_equal": 25,
- "rewrite_prefix": {
- "java.io.DesugarFile": "j$.io.DesugarFile",
- "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
- "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
- "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
- "java.nio.channels.Desugar": "j$.nio.channels.Desugar",
- "java.nio.file.": "j$.nio.file.",
- "jdk.internal.": "j$.jdk.internal.",
- "sun.misc.Desugar": "j$.sun.misc.Desugar",
- "sun.nio.cs.": "j$.sun.nio.cs.",
- "sun.nio.fs.AbstractFileSystemProvider": "j$.sun.nio.fs.AbstractFileSystemProvider",
- "sun.nio.fs.AbstractFileTypeDetector": "j$.sun.nio.fs.AbstractFileTypeDetector",
- "sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
- "sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
- "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap",
- "wrapper." : "j$.wrapper."
- },
- "rewrite_derived_prefix": {
- "java.nio.file.attribute.FileTime": {
- "j$.nio.file.attribute.FileTime": "java.nio.file.attribute.FileTime"
- },
- "java.io.": {
- "__wrapper__.j$.io.": "j$.io.",
- "__wrapper__.java.io.": "java.io."
- },
- "java.nio.": {
- "__wrapper__.j$.nio.": "j$.nio.",
- "__wrapper__.java.nio.": "java.nio."
- }
- },
- "retarget_method": {
- "boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)": "java.util.DesugarArrays"
- },
- "retarget_method_with_emulated_dispatch": {
- "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
},
"backport": {
"java.lang.DesugarDouble": "java.lang.Double",
"java.lang.DesugarInteger": "java.lang.Integer",
"java.lang.DesugarLong": "java.lang.Long",
"java.lang.DesugarMath": "java.lang.Math"
+ }
+ },
+ {
+ "api_level_below_or_equal": 25,
+ "retarget_method": {
+ "boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)": "java.util.DesugarArrays"
},
"amend_library_method": [
"private static boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)"
@@ -293,8 +225,6 @@
{
"api_level_below_or_equal": 23,
"rewrite_prefix": {
- "java.lang.FunctionalInterface": "j$.lang.FunctionalInterface",
- "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
"java.util.AbstractList": "j$.util.AbstractList",
"java.util.CollSer": "j$.util.CollSer",
"java.util.Comparators": "j$.util.Comparators",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
index 1985550..730a294 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
@@ -170,6 +170,7 @@
"api_level_below_or_equal": 30,
"rewrite_prefix": {
"j$.time.": "java.time.",
+ "jdk.internal.": "j$.jdk.internal.",
"sun.misc.Desugar": "j$.sun.misc.Desugar",
"sun.security.action.": "j$.sun.security.action."
},
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
similarity index 83%
copy from src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
copy to src/library_desugar/jdk11/desugar_jdk_libs_path.json
index 57f7c3e..092b976 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
@@ -1,9 +1,9 @@
{
- "identifier": "com.tools.android:desugar_jdk_libs_alternative_3:2.0.0",
+ "identifier": "com.tools.android:desugar_jdk_libs:2.0.0",
"configuration_format_version": 100,
"required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
- "support_all_callbacks_from_library": false,
+ "support_all_callbacks_from_library": true,
"common_flags": [
{
"api_level_below_or_equal": 32,
@@ -52,9 +52,68 @@
}
},
{
+ "api_level_below_or_equal": 25,
+ "rewrite_prefix": {
+ "java.io.DesugarFile": "j$.io.DesugarFile",
+ "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
+ "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
+ "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
+ "java.nio.file.": "j$.nio.file."
+ },
+ "retarget_method_with_emulated_dispatch": {
+ "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
+ },
+ "wrapper_conversion": [
+ "java.nio.channels.AsynchronousChannel",
+ "java.nio.channels.CompletionHandler",
+ "java.nio.file.Path",
+ "java.nio.file.FileSystem",
+ "java.nio.file.WatchService",
+ "java.nio.file.WatchEvent$Kind",
+ "java.nio.file.WatchKey",
+ "java.nio.file.Watchable",
+ "java.nio.file.PathMatcher",
+ "java.nio.file.WatchEvent$Modifier",
+ "java.nio.file.attribute.UserPrincipalLookupService",
+ "java.nio.file.spi.FileSystemProvider",
+ "java.nio.file.AccessMode",
+ "java.nio.file.LinkOption",
+ "java.nio.file.CopyOption",
+ "java.nio.file.attribute.GroupPrincipal",
+ "java.nio.file.attribute.FileAttribute",
+ "java.nio.file.attribute.FileAttributeView",
+ "java.nio.file.attribute.UserPrincipal",
+ "java.nio.file.FileStore",
+ "java.nio.file.attribute.FileStoreAttributeView",
+ "java.nio.file.DirectoryStream$Filter",
+ "java.nio.file.DirectoryStream",
+ "java.nio.file.OpenOption",
+ "java.nio.file.attribute.BasicFileAttributes"
+ ],
+ "wrapper_conversion_excluding": {
+ "java.nio.channels.AsynchronousFileChannel": [
+ "void java.nio.channels.AsynchronousFileChannel#lock(java.lang.Object, java.nio.channels.CompletionHandler)",
+ "java.util.concurrent.Future java.nio.channels.AsynchronousFileChannel#lock()",
+ "java.nio.channels.FileLock java.nio.channels.AsynchronousFileChannel#tryLock()"
+ ]
+ },
+ "custom_conversion": {
+ "java.nio.file.attribute.FileTime": "java.nio.file.attribute.FileAttributeConversions"
+ }
+ },
+ {
+ "api_level_below_or_equal": 32,
+ "api_level_greater_or_equal": 24,
+ "rewrite_prefix": {
+ "java.util.stream.Collectors": "j$.util.stream.Collectors"
+ }
+ },
+ {
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader",
+ "java.nio.channels.FileChannel": "j$.nio.channels.FileChannel",
+ "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -69,6 +128,9 @@
"java.util.function.": "j$.util.function.",
"java.util.stream.": "j$.util.stream."
},
+ "dont_rewrite_prefix": [
+ "java.nio.channels.FileChannel$MapMode"
+ ],
"maintain_prefix": [
"java.io.UncheckedIOException"
],
@@ -110,6 +172,7 @@
"java.util.Spliterator java.util.LinkedHashSet#spliterator()": "java.util.DesugarLinkedHashSet"
},
"wrapper_conversion": [
+ "java.nio.channels.SeekableByteChannel",
"java.util.function.IntUnaryOperator",
"java.util.function.BiFunction",
"java.util.function.IntConsumer",
@@ -164,6 +227,16 @@
"java.util.Spliterator": [
"boolean java.util.Spliterator#hasCharacteristics(int)",
"long java.util.Spliterator#getExactSizeIfKnown()"
+ ],
+ "java.nio.channels.FileChannel": [
+ "long java.nio.channels.FileChannel#read(java.nio.ByteBuffer[])",
+ "long java.nio.channels.FileChannel#write(java.nio.ByteBuffer[])",
+ "java.nio.channels.FileLock java.nio.channels.FileChannel#lock()",
+ "java.nio.channels.FileLock java.nio.channels.FileChannel#tryLock()",
+ "void java.nio.channels.spi.AbstractInterruptibleChannel#close()",
+ "boolean java.nio.channels.spi.AbstractInterruptibleChannel#isOpen()",
+ "void java.nio.channels.spi.AbstractInterruptibleChannel#begin()",
+ "void java.nio.channels.spi.AbstractInterruptibleChannel#end(boolean)"
]
},
"custom_conversion": {
@@ -198,6 +271,16 @@
}
},
{
+ "api_level_below_or_equal": 25,
+ "rewrite_prefix": {
+ "java.io.DesugarFile": "j$.io.DesugarFile",
+ "java.nio.file.": "j$.nio.file."
+ },
+ "retarget_method_with_emulated_dispatch": {
+ "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
+ }
+ },
+ {
"api_level_below_or_equal": 23,
"retarget_method": {
"int java.util.concurrent.atomic.AtomicInteger#accumulateAndGet(int, java.util.function.IntBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
@@ -245,12 +328,7 @@
{
"api_level_below_or_equal": 25,
"rewrite_prefix": {
- "java.io.DesugarFile": "j$.io.DesugarFile",
- "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
- "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
- "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
"java.nio.channels.Desugar": "j$.nio.channels.Desugar",
- "java.nio.file.": "j$.nio.file.",
"jdk.internal.": "j$.jdk.internal.",
"sun.misc.Desugar": "j$.sun.misc.Desugar",
"sun.nio.cs.": "j$.sun.nio.cs.",
@@ -259,27 +337,19 @@
"sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
"sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
"sun.util.PreHashedMap": "j$.sun.util.PreHashedMap",
- "wrapper." : "j$.wrapper."
+ "java.adapter" : "j$.adapter"
},
"rewrite_derived_prefix": {
"java.nio.file.attribute.FileTime": {
"j$.nio.file.attribute.FileTime": "java.nio.file.attribute.FileTime"
},
- "java.io.": {
- "__wrapper__.j$.io.": "j$.io.",
- "__wrapper__.java.io.": "java.io."
- },
- "java.nio.": {
- "__wrapper__.j$.nio.": "j$.nio.",
- "__wrapper__.java.nio.": "java.nio."
+ "java.nio.file.Files": {
+ "j$.nio.file.Files": "java.nio.file.Files"
}
},
"retarget_method": {
"boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)": "java.util.DesugarArrays"
},
- "retarget_method_with_emulated_dispatch": {
- "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
- },
"backport": {
"java.lang.DesugarDouble": "java.lang.Double",
"java.lang.DesugarInteger": "java.lang.Integer",
@@ -294,7 +364,6 @@
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.lang.FunctionalInterface": "j$.lang.FunctionalInterface",
- "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
"java.util.AbstractList": "j$.util.AbstractList",
"java.util.CollSer": "j$.util.CollSer",
"java.util.Comparators": "j$.util.Comparators",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json
similarity index 98%
rename from src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
rename to src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json
index 57f7c3e..5064ba5 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json
@@ -262,9 +262,6 @@
"wrapper." : "j$.wrapper."
},
"rewrite_derived_prefix": {
- "java.nio.file.attribute.FileTime": {
- "j$.nio.file.attribute.FileTime": "java.nio.file.attribute.FileTime"
- },
"java.io.": {
"__wrapper__.j$.io.": "j$.io.",
"__wrapper__.java.io.": "java.io."
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index acbd677..fe2ed57 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -146,6 +146,41 @@
}
/**
+ * Set a consumer for receiving the proguard-map content.
+ *
+ * <p>Note that when a proguard-map consumer is specified for a release build, the compiler will
+ * optimize the line-number information and obtaining a source-level stacktrace will require the
+ * use of a retrace tool exactly as is needed for programs built by R8.
+ *
+ * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
+ * override the previous setting.
+ *
+ * @param proguardMapConsumer Consumer to receive the content once produced.
+ */
+ @Override
+ public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
+ return super.setProguardMapConsumer(proguardMapConsumer);
+ }
+
+ /**
+ * Set an output destination to which proguard-map content should be written.
+ *
+ * <p>Note that when a proguard-map output is specified for a release build, the compiler will
+ * optimize the line-number information and obtaining a source-level stacktrace will require the
+ * use of a retrace tool exactly as is needed for programs built by R8.
+ *
+ * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
+ * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
+ * #setProguardMapConsumer} will override the previous setting.
+ *
+ * @param proguardMapOutput File-system path to write output at.
+ */
+ @Override
+ public Builder setProguardMapOutputPath(Path proguardMapOutput) {
+ return super.setProguardMapOutputPath(proguardMapOutput);
+ }
+
+ /**
* Indicate if compilation is to intermediate results, i.e., intended for later merging.
*
* <p>When compiling to intermediate mode, the compiler will avoid sharing of synthetic items,
@@ -376,6 +411,7 @@
getThreadCount(),
getDumpInputFlags(),
getMapIdProvider(),
+ proguardMapConsumer,
factory);
}
}
@@ -392,6 +428,7 @@
private final boolean enableMainDexListCheck;
private final boolean minimalMainDex;
private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
+ private final StringConsumer proguardMapConsumer;
private final DexItemFactory factory;
public static Builder builder() {
@@ -460,6 +497,7 @@
int threadCount,
DumpInputFlags dumpInputFlags,
MapIdProvider mapIdProvider,
+ StringConsumer proguardMapConsumer,
DexItemFactory factory) {
super(
inputApp,
@@ -488,6 +526,7 @@
this.enableMainDexListCheck = enableMainDexListCheck;
this.minimalMainDex = minimalMainDex;
this.mainDexKeepRules = mainDexKeepRules;
+ this.proguardMapConsumer = proguardMapConsumer;
this.factory = factory;
}
@@ -503,6 +542,7 @@
enableMainDexListCheck = true;
minimalMainDex = false;
mainDexKeepRules = null;
+ proguardMapConsumer = null;
factory = null;
}
@@ -532,7 +572,11 @@
internal.setGlobalSyntheticsConsumer(globalSyntheticsConsumer);
internal.desugarGraphConsumer = desugarGraphConsumer;
internal.mainDexKeepRules = mainDexKeepRules;
- internal.lineNumberOptimization = LineNumberOptimization.OFF;
+ internal.proguardMapConsumer = proguardMapConsumer;
+ internal.lineNumberOptimization =
+ !internal.debug && proguardMapConsumer != null
+ ? LineNumberOptimization.ON
+ : LineNumberOptimization.OFF;
// Assert and fixup defaults.
assert !internal.isShrinking();
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index 9e729e0..719120f 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -30,6 +30,7 @@
"--lib",
"--classpath",
"--pg-map",
+ "--pg-map-output",
MIN_API_FLAG,
"--main-dex-rules",
"--main-dex-list",
@@ -131,6 +132,9 @@
+ AndroidApiLevel.getDefault().getLevel()
+ ".",
" --pg-map <file> # Use <file> as a mapping file for distribution.",
+ // TODO(b/183125319): Add help info once supported.
+ // " --pg-map-output <file> # Enable line optimization and output mapping to"
+ // +" <file>.",
" --intermediate # Compile an intermediate result intended for later",
" # merging.",
" --file-per-class # Produce a separate dex file per class.",
@@ -226,6 +230,8 @@
outputMode = OutputMode.ClassFile;
} else if (arg.equals("--pg-map")) {
builder.setProguardInputMapFile(Paths.get(nextArg));
+ } else if (arg.equals("--pg-map-output")) {
+ builder.setProguardMapOutputPath(Paths.get(nextArg));
} else if (arg.equals("--output")) {
if (outputPath != null) {
builder.error(
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
deleted file mode 100644
index a7ac9e3..0000000
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8;
-
-import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
-
-import com.android.tools.r8.DexIndexedConsumer.DirectoryConsumer;
-import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.dex.ApplicationWriter;
-import com.android.tools.r8.dex.Marker;
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.LazyLoadedDexApplication;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.MainDexInfo;
-import com.android.tools.r8.utils.ExceptionUtils;
-import com.android.tools.r8.utils.FeatureClassMapping;
-import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.InternalOptions.DesugarState;
-import com.android.tools.r8.utils.ThreadUtils;
-import com.android.tools.r8.utils.Timing;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-@Keep
-public final class DexSplitterHelper {
-
- public static void run(
- D8Command command, FeatureClassMapping featureClassMapping, String output, String proguardMap)
- throws CompilationFailedException {
- ExecutorService executor = ThreadUtils.getExecutorService(ThreadUtils.NOT_SPECIFIED);
- try {
- ExceptionUtils.withCompilationHandler(
- command.getReporter(),
- () -> run(command, featureClassMapping, output, proguardMap, executor));
- } finally {
- executor.shutdown();
- }
- }
-
- public static void run(
- D8Command command,
- FeatureClassMapping featureClassMapping,
- String output,
- String proguardMap,
- ExecutorService executor)
- throws IOException {
- InternalOptions options = command.getInternalOptions();
- options.desugarState = DesugarState.OFF;
- options.enableMainDexListCheck = false;
- options.ignoreMainDexMissingClasses = true;
- options.minimalMainDex = false;
- assert !options.isMinifying();
- options.inlinerOptions().enableInlining = false;
- options.outline.enabled = false;
-
- try {
- Timing timing = new Timing("DexSplitter");
- ApplicationReader applicationReader =
- new ApplicationReader(command.getInputApp(), options, timing);
- DexApplication app = applicationReader.read(executor);
- MainDexInfo mainDexInfo = applicationReader.readMainDexClasses(app);
-
- List<Marker> markers = app.dexItemFactory.extractMarkers();
-
- ClassNameMapper mapper = null;
- if (proguardMap != null) {
- mapper = ClassNameMapper.mapperFromFile(Paths.get(proguardMap));
- }
- Map<String, LazyLoadedDexApplication.Builder> applications =
- getDistribution(app, featureClassMapping, mapper);
- for (Entry<String, LazyLoadedDexApplication.Builder> entry : applications.entrySet()) {
- String feature = entry.getKey();
- timing.begin("Feature " + feature);
- DexApplication featureApp = entry.getValue().build();
- assert !options.hasMethodsFilter();
-
- // If this is the base, we add the main dex list.
- AppInfo appInfo =
- feature.equals(featureClassMapping.getBaseName())
- ? AppInfo.createInitialAppInfo(featureApp, mainDexInfo)
- : AppInfo.createInitialAppInfo(featureApp);
- AppView<AppInfo> appView = AppView.createForD8(appInfo);
-
- // Run d8 optimize to ensure jumbo strings are handled.
- D8.optimize(appView, options, timing, executor);
-
- // We create a specific consumer for each split.
- Path outputDir = Paths.get(output).resolve(entry.getKey());
- if (!Files.exists(outputDir)) {
- Files.createDirectory(outputDir);
- }
- DexIndexedConsumer consumer = new DirectoryConsumer(outputDir);
-
- try {
- new ApplicationWriter(
- appView,
- markers,
- NamingLens.getIdentityLens(),
- consumer)
- .write(executor);
- options.printWarnings();
- } finally {
- consumer.finished(options.reporter);
- }
- timing.end();
- }
- } catch (ExecutionException e) {
- throw unwrapExecutionException(e);
- } catch (FeatureMappingException e) {
- options.reporter.error(e.getMessage());
- } finally {
- options.signalFinishedToConsumers();
- }
- }
-
- private static Map<String, LazyLoadedDexApplication.Builder> getDistribution(
- DexApplication app, FeatureClassMapping featureClassMapping, ClassNameMapper mapper)
- throws FeatureMappingException {
- Map<String, LazyLoadedDexApplication.Builder> applications = new HashMap<>();
- for (DexProgramClass clazz : app.classes()) {
- String clazzName =
- mapper != null ? mapper.deobfuscateClassName(clazz.toString()) : clazz.toString();
- String feature = featureClassMapping.featureForClass(clazzName);
- LazyLoadedDexApplication.Builder featureApplication = applications.get(feature);
- if (featureApplication == null) {
- featureApplication = DexApplication.builder(app.options, app.timing);
- applications.put(feature, featureApplication);
- }
- featureApplication.addProgramClass(clazz);
- }
- return applications;
- }
-
- public static void runD8ForTesting(D8Command command, boolean dontCreateMarkerInD8)
- throws CompilationFailedException {
- InternalOptions options = command.getInternalOptions();
- options.testing.dontCreateMarkerInD8 = dontCreateMarkerInD8;
- D8.runForTesting(command.getInputApp(), options);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 888b78b..7bdb3b9 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -986,7 +986,11 @@
internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification);
internal.synthesizedClassPrefix = synthesizedClassPrefix;
// TODO(b/214382176): Enable all the time.
- internal.loadAllClassDefinitions = !synthesizedClassPrefix.isEmpty();
+ boolean l8Shrinking = !synthesizedClassPrefix.isEmpty();
+ internal.loadAllClassDefinitions = l8Shrinking;
+ if (l8Shrinking) {
+ internal.apiModelingOptions().disableSubbingOfClasses();
+ }
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
// Set up the map and source file providers.
diff --git a/src/main/java/com/android/tools/r8/SwissArmyKnife.java b/src/main/java/com/android/tools/r8/SwissArmyKnife.java
index 2d836ae..2e44e14 100644
--- a/src/main/java/com/android/tools/r8/SwissArmyKnife.java
+++ b/src/main/java/com/android/tools/r8/SwissArmyKnife.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.bisect.Bisect;
import com.android.tools.r8.cf.CfVerifierTool;
import com.android.tools.r8.compatproguard.CompatProguard;
-import com.android.tools.r8.dexsplitter.DexSplitter;
import com.android.tools.r8.relocator.RelocatorCommandLine;
import com.android.tools.r8.tracereferences.TraceReferences;
import java.util.Arrays;
@@ -41,9 +40,6 @@
case "dexsegments":
DexSegments.main(shift(args));
break;
- case "dexsplitter":
- DexSplitter.main(shift(args));
- break;
case "disasm":
Disassemble.main(shift(args));
break;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index 67e44d4..af0b133 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -215,4 +216,16 @@
FrameType frameType = FrameType.fromNumericType(type, dexItemFactory);
frameBuilder.popAndDiscard(frameType, frameType).push(frameType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState state,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ..., value1, value2 →
+ // ..., result
+ FrameType frameType = FrameType.fromNumericType(type, dexItemFactory);
+ return state.pop(appView, frameType, frameType).push(frameType);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 35a03f2..cdd43c2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -20,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -91,4 +93,14 @@
.popAndDiscardInitialized(dexItemFactory.objectArrayType)
.push(dexItemFactory.intType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index dc6a732..5069f14 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -24,6 +25,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -136,4 +138,14 @@
frameBuilder.popAndDiscardInitialized(dexItemFactory.objectArrayType, dexItemFactory.intType);
frameBuilder.push(FrameType.fromMemberType(type, dexItemFactory));
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 39db93e..c51336f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -127,4 +129,14 @@
.popAndDiscard(FrameType.fromMemberType(type, dexItemFactory))
.popAndDiscardInitialized(dexItemFactory.objectArrayType, dexItemFactory.intType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
new file mode 100644
index 0000000..828a2f2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf.code;
+
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.MemberType;
+
+public class CfAssignability {
+
+ // Based on https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.2.
+ public static boolean isAssignable(FrameType source, FrameType target, AppView<?> appView) {
+ if (target.isTop()) {
+ return true;
+ }
+ if (source.isTop()) {
+ return false;
+ }
+ if (source.isWide() != target.isWide()) {
+ return false;
+ }
+ if (target.isOneWord() || target.isTwoWord()) {
+ return true;
+ }
+ if (source.isUninitializedThis() && target.isUninitializedThis()) {
+ return true;
+ }
+ if (source.isUninitializedNew() && target.isUninitializedNew()) {
+ // TODO(b/168190134): Allow for picking the offset from the target if not set.
+ DexType uninitializedNewTypeSource = source.getUninitializedNewType();
+ DexType uninitializedNewTypeTarget = target.getUninitializedNewType();
+ return uninitializedNewTypeSource == null
+ || uninitializedNewTypeTarget == null
+ || uninitializedNewTypeSource == uninitializedNewTypeTarget;
+ }
+ // TODO(b/168190267): Clean-up the lattice.
+ DexItemFactory factory = appView.dexItemFactory();
+ if (!source.isInitialized()
+ && target.isInitialized()
+ && target.getInitializedType() == factory.objectType) {
+ return true;
+ }
+ if (source.isInitialized() && target.isInitialized()) {
+ // Both are instantiated types and we resort to primitive tyoe/java type hierarchy checking.
+ return isAssignable(source.getInitializedType(), target.getInitializedType(), appView);
+ }
+ return false;
+ }
+
+ // Rules found at https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.2
+ public static boolean isAssignable(DexType source, DexType target, AppView<?> appView) {
+ DexItemFactory factory = appView.dexItemFactory();
+ source = byteCharShortOrBooleanToInt(source, factory);
+ target = byteCharShortOrBooleanToInt(target, factory);
+ if (source == target) {
+ return true;
+ }
+ if (source.isPrimitiveType() || target.isPrimitiveType()) {
+ return false;
+ }
+ // Both are now references - everything is assignable to object.
+ if (target == factory.objectType) {
+ return true;
+ }
+ // isAssignable(null, class(_, _)).
+ // isAssignable(null, arrayOf(_)).
+ if (source == DexItemFactory.nullValueType) {
+ return true;
+ }
+ if (target.isArrayType() != target.isArrayType()) {
+ return false;
+ }
+ if (target.isArrayType()) {
+ return isAssignable(
+ target.toArrayElementType(factory), target.toArrayElementType(factory), appView);
+ }
+ // TODO(b/166570659): Do a sub-type check that allows for missing classes in hierarchy.
+ return MemberType.fromDexType(source) == MemberType.fromDexType(target);
+ }
+
+ private static DexType byteCharShortOrBooleanToInt(DexType type, DexItemFactory factory) {
+ // byte, char, short and boolean has verification type int.
+ if (type.isByteType() || type.isCharType() || type.isShortType() || type.isBooleanType()) {
+ return factory.intType;
+ }
+ return type;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index edd6603..55dd90f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -140,4 +142,14 @@
// ..., objectref
frameBuilder.popAndDiscardInitialized(dexItemFactory.objectType).push(type);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index 5b3c937..4ca69a0 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -25,6 +26,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -140,4 +142,14 @@
FrameType frameType = FrameType.fromNumericType(type, dexItemFactory);
frameBuilder.popAndDiscard(frameType, frameType).push(dexItemFactory.intType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index abc6070..10240e5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -147,4 +149,14 @@
// ..., value
frameBuilder.push(dexItemFactory.classType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index 3416ff7..666da46 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -31,6 +31,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.ConstantDynamic;
@@ -234,4 +235,14 @@
// ..., value
frameBuilder.push(dexItemFactory.classType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index 48db7ef..2f79cea 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -111,4 +113,14 @@
// ..., value
frameBuilder.push(dexItemFactory.methodHandleType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 855690f..0cc8d78 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -22,6 +23,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -109,4 +111,14 @@
// ..., value
frameBuilder.push(dexItemFactory.methodTypeType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index d58b161..efcd063 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -20,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -81,4 +83,14 @@
// ..., value
frameBuilder.push(DexItemFactory.nullValueType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index b1d9c5b..cee2f4a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -21,6 +22,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import org.objectweb.asm.MethodVisitor;
@@ -238,4 +240,14 @@
// ..., value
frameBuilder.push(type.toPrimitiveType().toDexType(dexItemFactory));
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index f03e9c7..4e4a325 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
@@ -112,4 +113,15 @@
// ..., value
frameBuilder.push(dexItemFactory.stringType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ... →
+ // ..., value
+ return frame.push(dexItemFactory.stringType);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index cdc4235..5ab3742 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -24,6 +25,7 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -131,4 +133,14 @@
// ..., value
frameBuilder.push(dexItemFactory.stringType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index ce94d5d..80813e1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -3,27 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.code;
-import static com.android.tools.r8.utils.BiPredicateUtils.or;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
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.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.conversion.CfSourceCode;
-import com.android.tools.r8.ir.conversion.CfState;
-import com.android.tools.r8.ir.conversion.CfState.Slot;
-import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -32,20 +22,20 @@
public abstract class CfFieldInstruction extends CfInstruction {
- private final int opcode;
private final DexField field;
private final DexField declaringField;
private static void specify(StructuralSpecification<CfFieldInstruction, ?> spec) {
- spec.withInt(f -> f.opcode).withItem(f -> f.field).withItem(f -> f.declaringField);
+ spec.withInt(CfFieldInstruction::getOpcode)
+ .withItem(CfFieldInstruction::getField)
+ .withItem(CfFieldInstruction::getDeclaringField);
}
- public CfFieldInstruction(int opcode, DexField field) {
- this(opcode, field, field);
+ public CfFieldInstruction(DexField field) {
+ this(field, field);
}
- public CfFieldInstruction(int opcode, DexField field, DexField declaringField) {
- this.opcode = opcode;
+ public CfFieldInstruction(DexField field, DexField declaringField) {
this.field = field;
this.declaringField = declaringField;
assert field.type == declaringField.type;
@@ -70,13 +60,15 @@
return field;
}
- public int getOpcode() {
- return opcode;
+ public DexField getDeclaringField() {
+ return declaringField;
}
+ public abstract int getOpcode();
+
@Override
public int getCompareToId() {
- return opcode;
+ return getOpcode();
}
@Override
@@ -86,15 +78,15 @@
}
public boolean isFieldGet() {
- return opcode == Opcodes.GETFIELD || opcode == Opcodes.GETSTATIC;
+ return false;
}
public boolean isStaticFieldGet() {
- return opcode == Opcodes.GETSTATIC;
+ return false;
}
public boolean isStaticFieldPut() {
- return opcode == Opcodes.PUTSTATIC;
+ return false;
}
public abstract CfFieldInstruction createWithField(DexField field);
@@ -124,7 +116,7 @@
String owner = namingLens.lookupInternalName(rewrittenField.holder);
String name = namingLens.lookupName(rewrittenDeclaringField).toString();
String desc = namingLens.lookupDescriptor(rewrittenField.type).toString();
- visitor.visitFieldInsn(opcode, owner, name, desc);
+ visitor.visitFieldInsn(getOpcode(), owner, name, desc);
}
@Override
@@ -141,92 +133,4 @@
public boolean canThrow() {
return true;
}
-
- @Override
- public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
- DexType type = field.type;
- switch (opcode) {
- case Opcodes.GETSTATIC:
- {
- builder.addStaticGet(state.push(type).register, field);
- break;
- }
- case Opcodes.PUTSTATIC:
- {
- Slot value = state.pop();
- builder.addStaticPut(value.register, field);
- break;
- }
- case Opcodes.GETFIELD:
- {
- Slot object = state.pop();
- builder.addInstanceGet(state.push(type).register, object.register, field);
- break;
- }
- case Opcodes.PUTFIELD:
- {
- Slot value = state.pop();
- Slot object = state.pop();
- builder.addInstancePut(value.register, object.register, field);
- break;
- }
- default:
- throw new Unreachable("Unexpected opcode " + opcode);
- }
- }
-
- @Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- switch (opcode) {
- case Opcodes.GETSTATIC:
- return inliningConstraints.forStaticGet(field, context);
- case Opcodes.PUTSTATIC:
- return inliningConstraints.forStaticPut(field, context);
- case Opcodes.GETFIELD:
- return inliningConstraints.forInstanceGet(field, context);
- case Opcodes.PUTFIELD:
- return inliningConstraints.forInstancePut(field, context);
- default:
- throw new Unreachable("Unexpected opcode " + opcode);
- }
- }
-
- @Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- switch (opcode) {
- case Opcodes.GETFIELD:
- // ..., objectref →
- // ..., value
- frameBuilder.popAndDiscardInitialized(field.holder).push(field.type);
- return;
- case Opcodes.GETSTATIC:
- // ..., →
- // ..., value
- frameBuilder.push(field.type);
- return;
- case Opcodes.PUTFIELD:
- // ..., objectref, value →
- // ...,
- frameBuilder
- .popAndDiscardInitialized(field.type)
- .pop(
- field.holder,
- or(
- frameBuilder::isUninitializedThisAndTarget,
- frameBuilder::isAssignableAndInitialized));
- return;
- case Opcodes.PUTSTATIC:
- // ..., value →
- // ...
- frameBuilder.popAndDiscardInitialized(field.type);
- return;
- default:
- throw new Unreachable("Unexpected opcode " + opcode);
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index 7f7f08b..e7b8c99 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -6,6 +6,7 @@
import static org.objectweb.asm.Opcodes.F_NEW;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -26,6 +27,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -377,12 +379,6 @@
return locals;
}
- // This is used from tests. As fastutils are repackaged and minified the method above is
- // not available from tests which use fastutils in their original namespace.
- public SortedMap<Integer, FrameType> getLocalsAsSortedMap() {
- return locals;
- }
-
public Deque<FrameType> getStack() {
return stack;
}
@@ -504,6 +500,16 @@
frameBuilder.checkFrameAndSet(this);
}
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+
public CfFrame markInstantiated(FrameType uninitializedType, DexType initType) {
if (uninitializedType.isInitialized()) {
throw CfCodeStackMapValidatingException.error(
@@ -520,7 +526,8 @@
return new CfFrame(newLocals, newStack);
}
- private FrameType getInitializedFrameType(FrameType unInit, FrameType other, DexType newType) {
+ public static FrameType getInitializedFrameType(
+ FrameType unInit, FrameType other, DexType newType) {
assert !unInit.isInitialized();
if (other.isInitialized()) {
return other;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
index c81abe4..aad0ba6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.utils.BiPredicateUtils.or;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCodeStackMapValidatingException;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
@@ -27,17 +28,16 @@
public class CfFrameVerificationHelper {
- private final CfFrame NO_FRAME =
+ private static final CfFrame NO_FRAME =
new CfFrame(
ImmutableInt2ReferenceSortedMap.<FrameType>builder().build(), ImmutableDeque.of());
- private final Deque<FrameType> throwStack;
+ private final AppView<?> appView;
+ private final DexItemFactory factory;
private CfFrame currentFrame = NO_FRAME;
private final DexType context;
private final Map<CfLabel, CfFrame> stateMap;
- private final BiPredicate<DexType, DexType> isJavaAssignable;
- private final DexItemFactory factory;
private final List<CfTryCatch> tryCatchRanges;
private final int maxStackHeight;
@@ -45,19 +45,17 @@
private final Set<CfLabel> tryCatchRangeLabels;
public CfFrameVerificationHelper(
+ AppView<?> appView,
DexType context,
Map<CfLabel, CfFrame> stateMap,
List<CfTryCatch> tryCatchRanges,
- BiPredicate<DexType, DexType> isJavaAssignable,
- DexItemFactory factory,
int maxStackHeight) {
+ this.appView = appView;
this.context = context;
this.stateMap = stateMap;
this.tryCatchRanges = tryCatchRanges;
- this.isJavaAssignable = isJavaAssignable;
- this.factory = factory;
+ this.factory = appView.dexItemFactory();
this.maxStackHeight = maxStackHeight;
- throwStack = ImmutableDeque.of(FrameType.initialized(factory.throwableType));
// Compute all labels that marks a start or end to catch ranges.
tryCatchRangeLabels = Sets.newIdentityHashSet();
for (CfTryCatch tryCatchRange : tryCatchRanges) {
@@ -66,10 +64,6 @@
}
}
- public DexItemFactory factory() {
- return factory;
- }
-
public FrameType readLocal(int index, DexType expectedType) {
checkFrameIsSet();
FrameType frameType = currentFrame.getLocals().get(index);
@@ -197,15 +191,12 @@
// From the spec: the handler's exception class is assignable to the class Throwable.
tryCatchRange.guards.forEach(
guard -> {
- if (!isJavaAssignable.test(guard, factory.throwableType)) {
+ if (!CfAssignability.isAssignable(guard, factory.throwableType, appView)) {
throw CfCodeStackMapValidatingException.error(
"Could not assign '" + guard.toSourceString() + "' to throwable.");
}
checkStackIsAssignable(
- ImmutableDeque.of(FrameType.initialized(guard)),
- destinationFrame.getStack(),
- factory,
- isJavaAssignable);
+ ImmutableDeque.of(FrameType.initialized(guard)), destinationFrame.getStack());
});
});
}
@@ -237,8 +228,7 @@
if (destinationFrame == null) {
throw CfCodeStackMapValidatingException.error("No frame for target catch range target");
}
- checkLocalsIsAssignable(
- currentFrame.getLocals(), destinationFrame.getLocals(), factory, isJavaAssignable);
+ checkLocalsIsAssignable(currentFrame.getLocals(), destinationFrame.getLocals());
}
}
}
@@ -259,13 +249,7 @@
}
public void checkFrame(Int2ReferenceSortedMap<FrameType> locals, Deque<FrameType> stack) {
- checkIsAssignable(
- currentFrame.getLocals(),
- currentFrame.getStack(),
- locals,
- stack,
- factory,
- isJavaAssignable);
+ checkIsAssignable(currentFrame.getLocals(), currentFrame.getStack(), locals, stack);
}
public void setNoFrame() {
@@ -290,7 +274,7 @@
if (!source.isInitialized()) {
return false;
}
- return isJavaAssignable.test(source.getInitializedType(), target);
+ return CfAssignability.isAssignable(source.getInitializedType(), target, appView);
}
public void checkIsAssignable(
@@ -303,31 +287,28 @@
}
public void checkIsAssignable(FrameType source, FrameType target) {
- if (!canBeAssigned(source, target, factory, isJavaAssignable)) {
+ if (!CfAssignability.isAssignable(source, target, appView)) {
throw CfCodeStackMapValidatingException.error(
"The expected type " + source + " is not assignable to " + target);
}
}
// Based on https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.4.
- public static void checkIsAssignable(
+ private void checkIsAssignable(
Int2ReferenceSortedMap<FrameType> sourceLocals,
Deque<FrameType> sourceStack,
Int2ReferenceSortedMap<FrameType> destLocals,
- Deque<FrameType> destStack,
- DexItemFactory factory,
- BiPredicate<DexType, DexType> isJavaAssignable) {
- checkLocalsIsAssignable(sourceLocals, destLocals, factory, isJavaAssignable);
- checkStackIsAssignable(sourceStack, destStack, factory, isJavaAssignable);
+ Deque<FrameType> destStack) {
+ checkLocalsIsAssignable(sourceLocals, destLocals);
+ checkStackIsAssignable(sourceStack, destStack);
}
- private static void checkLocalsIsAssignable(
+ private void checkLocalsIsAssignable(
Int2ReferenceSortedMap<FrameType> sourceLocals,
- Int2ReferenceSortedMap<FrameType> destLocals,
- DexItemFactory factory,
- BiPredicate<DexType, DexType> isJavaAssignable) {
- final int localsLastKey = sourceLocals.isEmpty() ? -1 : sourceLocals.lastIntKey();
- final int otherLocalsLastKey = destLocals.isEmpty() ? -1 : destLocals.lastIntKey();
+ Int2ReferenceSortedMap<FrameType> destLocals) {
+ // TODO(b/229826687): The tail of locals could have top(s) at destination but still be valid.
+ int localsLastKey = sourceLocals.isEmpty() ? -1 : sourceLocals.lastIntKey();
+ int otherLocalsLastKey = destLocals.isEmpty() ? -1 : destLocals.lastIntKey();
if (localsLastKey < otherLocalsLastKey) {
throw CfCodeStackMapValidatingException.error(
"Source locals "
@@ -336,11 +317,9 @@
+ MapUtils.toString(destLocals));
}
for (int i = 0; i < otherLocalsLastKey; i++) {
- final FrameType sourceType =
- sourceLocals.containsKey(i) ? sourceLocals.get(i) : FrameType.top();
- final FrameType destinationType =
- destLocals.containsKey(i) ? destLocals.get(i) : FrameType.top();
- if (!canBeAssigned(sourceType, destinationType, factory, isJavaAssignable)) {
+ FrameType sourceType = sourceLocals.containsKey(i) ? sourceLocals.get(i) : FrameType.top();
+ FrameType destinationType = destLocals.containsKey(i) ? destLocals.get(i) : FrameType.top();
+ if (!CfAssignability.isAssignable(sourceType, destinationType, appView)) {
throw CfCodeStackMapValidatingException.error(
"Could not assign '"
+ MapUtils.toString(sourceLocals)
@@ -357,11 +336,7 @@
}
}
- private static void checkStackIsAssignable(
- Deque<FrameType> sourceStack,
- Deque<FrameType> destStack,
- DexItemFactory factory,
- BiPredicate<DexType, DexType> isJavaAssignable) {
+ private void checkStackIsAssignable(Deque<FrameType> sourceStack, Deque<FrameType> destStack) {
if (sourceStack.size() != destStack.size()) {
throw CfCodeStackMapValidatingException.error(
"Source stack "
@@ -370,11 +345,11 @@
+ Arrays.toString(destStack.toArray())
+ " is not the same size");
}
- final Iterator<FrameType> otherIterator = destStack.iterator();
+ Iterator<FrameType> otherIterator = destStack.iterator();
int i = 0;
for (FrameType sourceType : sourceStack) {
- final FrameType destinationType = otherIterator.next();
- if (!canBeAssigned(sourceType, destinationType, factory, isJavaAssignable)) {
+ FrameType destinationType = otherIterator.next();
+ if (!CfAssignability.isAssignable(sourceType, destinationType, appView)) {
throw CfCodeStackMapValidatingException.error(
"Could not assign '"
+ Arrays.toString(sourceStack.toArray())
@@ -391,46 +366,4 @@
i++;
}
}
-
- // Based on https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.2.
- public static boolean canBeAssigned(
- FrameType source,
- FrameType target,
- DexItemFactory factory,
- BiPredicate<DexType, DexType> isJavaAssignable) {
- if (target.isTop()) {
- return true;
- }
- if (source.isTop()) {
- return false;
- }
- if (source.isWide() != target.isWide()) {
- return false;
- }
- if (target.isOneWord() || target.isTwoWord()) {
- return true;
- }
- if (source.isUninitializedThis() && target.isUninitializedThis()) {
- return true;
- }
- if (source.isUninitializedNew() && target.isUninitializedNew()) {
- // TODO(b/168190134): Allow for picking the offset from the target if not set.
- DexType uninitializedNewTypeSource = source.getUninitializedNewType();
- DexType uninitializedNewTypeTarget = target.getUninitializedNewType();
- return uninitializedNewTypeSource == null
- || uninitializedNewTypeTarget == null
- || uninitializedNewTypeSource == uninitializedNewTypeTarget;
- }
- // TODO(b/168190267): Clean-up the lattice.
- if (!source.isInitialized()
- && target.isInitialized()
- && target.getInitializedType() == factory.objectType) {
- return true;
- }
- if (source.isInitialized() && target.isInitialized()) {
- // Both are instantiated types and we resort to primitive tyoe/java type hierarchy checking.
- return isJavaAssignable.test(source.getInitializedType(), target.getInitializedType());
- }
- return false;
- }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index fa3a8a5..ee4b0f2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -19,7 +20,10 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
+import java.util.function.BiFunction;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -63,6 +67,14 @@
}
@Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ return fn.apply(target, initialValue);
+ }
+
+ @Override
public void write(
AppView<?> appView,
ProgramMethod context,
@@ -105,4 +117,14 @@
frameBuilder.checkTarget(target);
frameBuilder.setNoFrame();
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index 833ac44..d2fbccd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,7 +24,10 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
+import java.util.function.BiFunction;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -66,6 +70,16 @@
return target;
}
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ return fn.apply(target, initialValue)
+ .ifContinueThen(
+ continuation -> fn.apply(fallthroughInstruction, continuation.getValueOrDefault(null)));
+ }
+
public int getOpcode() {
switch (kind) {
case EQ:
@@ -146,4 +160,14 @@
: type.toPrimitiveType().toDexType(dexItemFactory));
frameBuilder.checkTarget(target);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index c8129a6..f6d94b7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -24,7 +25,10 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
+import java.util.function.BiFunction;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -67,6 +71,16 @@
return target;
}
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ return fn.apply(target, initialValue)
+ .ifContinueThen(
+ continuation -> fn.apply(fallthroughInstruction, continuation.getValueOrDefault(null)));
+ }
+
public int getOpcode() {
switch (kind) {
case EQ:
@@ -149,4 +163,14 @@
frameBuilder.popAndDiscardInitialized(type, type);
frameBuilder.checkTarget(target);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 1b5763c..046fca2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -20,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import org.objectweb.asm.MethodVisitor;
@@ -102,4 +104,14 @@
DexItemFactory dexItemFactory) {
frameBuilder.readLocal(var, dexItemFactory.intType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index c307d45..4df1ecd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -124,4 +126,14 @@
// ..., value
frameBuilder.push(dexItemFactory.intType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
index 2684c0d..df84afd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -5,9 +5,22 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
+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.DexClassAndMethod;
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.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.conversion.CfSourceCode;
+import com.android.tools.r8.ir.conversion.CfState;
+import com.android.tools.r8.ir.conversion.CfState.Slot;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import java.util.ListIterator;
import org.objectweb.asm.Opcodes;
@@ -18,7 +31,17 @@
}
public CfInstanceFieldRead(DexField field, DexField declaringField) {
- super(Opcodes.GETFIELD, field, declaringField);
+ super(field, declaringField);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcodes.GETFIELD;
+ }
+
+ @Override
+ public boolean isFieldGet() {
+ return true;
}
@Override
@@ -31,4 +54,37 @@
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceFieldReadInstruction(this);
}
+
+ @Override
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
+ Slot object = state.pop();
+ builder.addInstanceGet(state.push(getField().getType()).register, object.register, getField());
+ }
+
+ @Override
+ public ConstraintWithTarget inliningConstraint(
+ InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
+ return inliningConstraints.forInstanceGet(getField(), context);
+ }
+
+ @Override
+ public void evaluate(
+ CfFrameVerificationHelper frameBuilder,
+ DexMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ..., objectref →
+ // ..., value
+ frameBuilder.popAndDiscardInitialized(getField().getHolderType()).push(getField().getType());
+ }
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
index c9138bb..03766dd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -4,9 +4,24 @@
package com.android.tools.r8.cf.code;
+import static com.android.tools.r8.utils.BiPredicateUtils.or;
+
+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.DexClassAndMethod;
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.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.conversion.CfSourceCode;
+import com.android.tools.r8.ir.conversion.CfState;
+import com.android.tools.r8.ir.conversion.CfState.Slot;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import java.util.ListIterator;
import org.objectweb.asm.Opcodes;
@@ -17,7 +32,7 @@
}
public CfInstanceFieldWrite(DexField field, DexField declaringField) {
- super(Opcodes.PUTFIELD, field, declaringField);
+ super(field, declaringField);
}
@Override
@@ -26,8 +41,53 @@
}
@Override
+ public int getOpcode() {
+ return Opcodes.PUTFIELD;
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceFieldWrite(getField());
}
+
+ @Override
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
+ Slot value = state.pop();
+ Slot object = state.pop();
+ builder.addInstancePut(value.register, object.register, getField());
+ }
+
+ @Override
+ public ConstraintWithTarget inliningConstraint(
+ InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
+ return inliningConstraints.forInstancePut(getField(), context);
+ }
+
+ @Override
+ public void evaluate(
+ CfFrameVerificationHelper frameBuilder,
+ DexMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ..., objectref, value →
+ // ...,
+ frameBuilder
+ .popAndDiscardInitialized(getField().getType())
+ .pop(
+ getField().getHolderType(),
+ or(
+ frameBuilder::isUninitializedThisAndTarget,
+ frameBuilder::isAssignableAndInitialized));
+ }
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index 0469499..da48878 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -22,6 +23,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -134,4 +136,14 @@
// ..., result
frameBuilder.popAndDiscardInitialized(dexItemFactory.objectType).push(dexItemFactory.intType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 40b9737..7f449e6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -25,8 +25,12 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
import org.objectweb.asm.MethodVisitor;
public abstract class CfInstruction implements CfOrDexInstruction {
@@ -106,6 +110,26 @@
return null;
}
+ public final void forEachNormalTarget(
+ Consumer<? super CfInstruction> consumer, CfInstruction fallthroughInstruction) {
+ traverseNormalTargets(
+ (target, ignore) -> {
+ consumer.accept(target);
+ return TraversalContinuation.doContinue();
+ },
+ fallthroughInstruction,
+ null);
+ }
+
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ // The method is overridden in each jump instruction.
+ assert !isJump();
+ return fn.apply(fallthroughInstruction, initialValue);
+ }
+
@Override
public CfInstruction asCfInstruction() {
return this;
@@ -317,4 +341,7 @@
DexMethod context,
AppView<?> appView,
DexItemFactory dexItemFactory);
+
+ public abstract CfFrameState evaluate(
+ CfFrameState frame, ProgramMethod context, AppView<?> appView, DexItemFactory dexItemFactory);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 8397bc6..c972e4e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -32,6 +32,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Arrays;
@@ -337,6 +338,30 @@
}
}
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ..., objectref, [arg1, [arg2 ...]] →
+ // ... [ returnType ]
+ // OR, for static method calls:
+ // ..., [arg1, [arg2 ...]] →
+ // ...
+ frame = frame.popInitialized(appView, method.getParameters().getBacking());
+ if (opcode != Opcodes.INVOKESTATIC) {
+ frame =
+ opcode == Opcodes.INVOKESPECIAL && context.getDefinition().isInstanceInitializer()
+ ? frame.popAndInitialize(appView, method, context)
+ : frame.popInitialized(appView, method.getHolderType());
+ }
+ if (method.getReturnType().isVoidType()) {
+ return frame;
+ }
+ return frame.push(method.getReturnType());
+ }
+
private Type computeInvokeTypeForInvokeSpecial(
AppView<?> appView, DexMethod method, ProgramMethod context, DexType originalHolder) {
if (appView.dexItemFactory().isConstructor(method)) {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index a02060b..421902e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -28,6 +29,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ArrayList;
import java.util.List;
@@ -178,4 +180,14 @@
frameBuilder.push(callSite.methodProto.returnType);
}
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index bc866cb..41e1063 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
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.CfCodeStackMapValidatingException;
@@ -21,6 +22,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
@@ -93,6 +95,16 @@
throw CfCodeStackMapValidatingException.error("Unexpected JSR/RET instruction");
}
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+
public int getLocal() {
return local;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 3df1eba..4bd20a2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -19,6 +20,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -102,4 +104,14 @@
DexItemFactory dexItemFactory) {
frameBuilder.seenLabel(this);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 99a32da..889d4aa 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -22,6 +23,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -139,4 +141,14 @@
? dexItemFactory.objectType
: type.toPrimitiveType().toDexType(dexItemFactory)));
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 2407b10..a5ee7eb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -197,4 +199,14 @@
}
frameBuilder.popAndDiscard(value1Type, value2Type).push(value1Type);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index 11df4ee..85ddc69 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+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.CfCompareHelper;
@@ -22,6 +23,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -103,4 +105,14 @@
// ...
frameBuilder.pop(FrameType.initialized(dexItemFactory.objectType));
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 509e0cf..796a93f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -22,6 +23,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -140,4 +142,14 @@
}
frameBuilder.push(type);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index da12fc5..9c6a7f8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -129,4 +131,14 @@
FrameType frameType = FrameType.fromNumericType(type, dexItemFactory);
frameBuilder.popAndDiscard(frameType).push(frameType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index b4c070a..0fde2a7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -123,4 +124,15 @@
// ..., objectref
frameBuilder.push(FrameType.uninitializedNew(new CfLabel(), type));
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ... →
+ // ..., objectref
+ return frame.push(FrameType.uninitializedNew(new CfLabel(), type));
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 5149789..ba81a58 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -24,6 +25,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
@@ -174,4 +176,14 @@
assert type.isArrayType();
frameBuilder.popAndDiscardInitialized(dexItemFactory.intType).push(type);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index 0c75328..8683ddd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -24,6 +25,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ListIterator;
import org.objectweb.asm.MethodVisitor;
@@ -126,4 +128,14 @@
// ..., objectref
frameBuilder.push(FrameType.initialized(type));
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index f77241e..e8b3a2e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -19,6 +20,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -83,4 +85,14 @@
DexItemFactory dexItemFactory) {
// This is an actual Nop.
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index b8fe9c1..0341487 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -201,4 +203,14 @@
.popAndDiscard(FrameType.fromNumericType(from, dexItemFactory))
.push(FrameType.fromNumericType(to, dexItemFactory));
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index 6f82c07..155b17d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -20,6 +21,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
@@ -116,4 +118,14 @@
DexItemFactory dexItemFactory) {
// This is a no-op.
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index f8fad92..4a9fd91 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,6 +24,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import it.unimi.dsi.fastutil.ints.IntArrayList;
@@ -119,4 +121,14 @@
}
frameBuilder.push(dexItemFactory.objectArrayType);
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index d06db87..27b73f6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -22,7 +23,10 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
+import java.util.function.BiFunction;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -72,6 +76,14 @@
}
@Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ return TraversalContinuation.doContinue(initialValue);
+ }
+
+ @Override
public boolean isJump() {
return true;
}
@@ -121,4 +133,14 @@
frameBuilder.popAndDiscardInitialized(context.getReturnType());
frameBuilder.setNoFrame();
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index d492b04..a61642f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -19,13 +19,24 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
+import java.util.function.BiFunction;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class CfReturnVoid extends CfInstruction {
@Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ return TraversalContinuation.doContinue(initialValue);
+ }
+
+ @Override
public boolean isJump() {
return true;
}
@@ -93,4 +104,13 @@
DexItemFactory dexItemFactory) {
frameBuilder.setNoFrame();
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ return CfFrameState.bottom();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index 366033d..5f5e5a9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -24,6 +25,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -358,7 +360,6 @@
DexMethod context,
AppView<?> appView,
DexItemFactory dexItemFactory) {
-
switch (opcode) {
case Pop:
// ..., value →
@@ -513,4 +514,61 @@
throw new Unreachable("Invalid opcode for CfStackInstruction");
}
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ switch (opcode) {
+ case Pop:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ case Pop2:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ case Dup:
+ // ..., value →
+ // ..., value, value
+ return frame.pop(
+ appView, FrameType.oneWord(), frameType -> frame.push(frameType).push(frameType));
+ case DupX1:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ case DupX2:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ case Dup2:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ case Dup2X1:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ case Dup2X2:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ case Swap:
+ {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ default:
+ throw new Unreachable("Invalid opcode for CfStackInstruction");
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
index 30715e1..3950a9c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
@@ -5,20 +5,31 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.code.CfOrDexStaticFieldRead;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexClassAndMethod;
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.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.conversion.CfSourceCode;
+import com.android.tools.r8.ir.conversion.CfState;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import java.util.ListIterator;
import org.objectweb.asm.Opcodes;
public class CfStaticFieldRead extends CfFieldInstruction implements CfOrDexStaticFieldRead {
public CfStaticFieldRead(DexField field) {
- super(Opcodes.GETSTATIC, field);
+ super(field);
}
public CfStaticFieldRead(DexField field, DexField declaringField) {
- super(Opcodes.GETSTATIC, field, declaringField);
+ super(field, declaringField);
}
@Override
@@ -27,8 +38,56 @@
}
@Override
+ public int getOpcode() {
+ return Opcodes.GETSTATIC;
+ }
+
+ @Override
+ public boolean isFieldGet() {
+ return true;
+ }
+
+ @Override
+ public boolean isStaticFieldGet() {
+ return true;
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerStaticFieldReadInstruction(this);
}
+
+ @Override
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
+ builder.addStaticGet(state.push(getField().getType()).register, getField());
+ }
+
+ @Override
+ public ConstraintWithTarget inliningConstraint(
+ InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
+ return inliningConstraints.forStaticGet(getField(), context);
+ }
+
+ @Override
+ public void evaluate(
+ CfFrameVerificationHelper frameBuilder,
+ DexMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ..., →
+ // ..., value
+ frameBuilder.push(getField().getType());
+ }
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ..., →
+ // ..., value
+ return frame.push(getField().getType());
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
index 24b5e6d..26114d8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -4,20 +4,33 @@
package com.android.tools.r8.cf.code;
+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.DexClassAndMethod;
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.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.conversion.CfSourceCode;
+import com.android.tools.r8.ir.conversion.CfState;
+import com.android.tools.r8.ir.conversion.CfState.Slot;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import java.util.ListIterator;
import org.objectweb.asm.Opcodes;
public class CfStaticFieldWrite extends CfFieldInstruction {
public CfStaticFieldWrite(DexField field) {
- super(Opcodes.PUTSTATIC, field);
+ super(field);
}
public CfStaticFieldWrite(DexField field, DexField declaringField) {
- super(Opcodes.PUTSTATIC, field, declaringField);
+ super(field, declaringField);
}
@Override
@@ -26,8 +39,51 @@
}
@Override
+ public int getOpcode() {
+ return Opcodes.PUTSTATIC;
+ }
+
+ @Override
+ public boolean isStaticFieldPut() {
+ return true;
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerStaticFieldWrite(getField());
}
+
+ @Override
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
+ Slot value = state.pop();
+ builder.addStaticPut(value.register, getField());
+ }
+
+ @Override
+ public ConstraintWithTarget inliningConstraint(
+ InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
+ return inliningConstraints.forStaticPut(getField(), context);
+ }
+
+ @Override
+ public void evaluate(
+ CfFrameVerificationHelper frameBuilder,
+ DexMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // ..., value →
+ // ...
+ frameBuilder.popAndDiscardInitialized(getField().getType());
+ }
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index 616ed84..e095dc8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -25,6 +26,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -172,4 +174,14 @@
throw new Unreachable("Unexpected type " + type);
}
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index a86bcd1..ea40b51 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -21,9 +22,13 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
+import com.android.tools.r8.utils.TraversalUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.List;
+import java.util.function.BiFunction;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -47,6 +52,16 @@
}
@Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ return TraversalUtils.traverseIterable(targets, fn, initialValue)
+ .ifContinueThen(
+ continuation -> fn.apply(defaultTarget, continuation.getValueOrDefault(null)));
+ }
+
+ @Override
public int getCompareToId() {
return kind == Kind.LOOKUP ? Opcodes.LOOKUPSWITCH : Opcodes.TABLESWITCH;
}
@@ -171,4 +186,14 @@
}
frameBuilder.setNoFrame();
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index 6e5eb78..d0aa3f8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.CfCompareHelper;
@@ -20,13 +21,24 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
+import java.util.function.BiFunction;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class CfThrow extends CfInstruction {
@Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalTargets(
+ BiFunction<? super CfInstruction, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CfInstruction fallthroughInstruction,
+ CT initialValue) {
+ return TraversalContinuation.doContinue(initialValue);
+ }
+
+ @Override
public boolean isJump() {
return true;
}
@@ -104,4 +116,14 @@
// The exception edges are verified in CfCode since this is a throwing instruction.
frameBuilder.setNoFrame();
}
+
+ @Override
+ public CfFrameState evaluate(
+ CfFrameState frame,
+ ProgramMethod context,
+ AppView<?> appView,
+ DexItemFactory dexItemFactory) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java b/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java
index 2f821be..22aac9a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
public class CfTryCatch {
public final CfLabel start;
@@ -28,6 +29,22 @@
assert verifyAllNonNull(guards);
}
+ public void forEachTarget(Consumer<CfLabel> consumer) {
+ targets.forEach(consumer);
+ }
+
+ public CfLabel getStart() {
+ return start;
+ }
+
+ public CfLabel getEnd() {
+ return end;
+ }
+
+ public List<CfLabel> getTargets() {
+ return targets;
+ }
+
private static boolean verifyAllNonNull(List<DexType> types) {
for (DexType type : types) {
assert type != null;
diff --git a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java b/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
deleted file mode 100644
index 4ee416c..0000000
--- a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
+++ /dev/null
@@ -1,377 +0,0 @@
-// Copyright (c) 2018, 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.dexsplitter;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.DexSplitterHelper;
-import com.android.tools.r8.Diagnostic;
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.Keep;
-import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.utils.AbortException;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
-import com.android.tools.r8.utils.ExceptionUtils;
-import com.android.tools.r8.utils.FeatureClassMapping;
-import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
-import com.android.tools.r8.utils.OptionsParsing;
-import com.android.tools.r8.utils.OptionsParsing.ParseContext;
-import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.ZipUtils;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-@Keep
-public final class DexSplitter {
-
- private static final String DEFAULT_OUTPUT_DIR = "output";
- private static final String DEFAULT_BASE_NAME = "base";
-
- private static final boolean PRINT_ARGS = false;
-
- public static class FeatureJar {
- private String jar;
- private String outputName;
-
- public FeatureJar(String jar, String outputName) {
- this.jar = jar;
- this.outputName = outputName;
- }
-
- public FeatureJar(String jar) {
- this(jar, featureNameFromJar(jar));
- }
-
- public String getJar() {
- return jar;
- }
-
- public String getOutputName() {
- return outputName;
- }
-
- private static String featureNameFromJar(String jar) {
- Path jarPath = Paths.get(jar);
- String featureName = jarPath.getFileName().toString();
- if (featureName.endsWith(".jar") || featureName.endsWith(".zip")) {
- featureName = featureName.substring(0, featureName.length() - 4);
- }
- return featureName;
- }
- }
-
- private static class ZipFileOrigin extends PathOrigin {
-
- public ZipFileOrigin(Path path) {
- super(path);
- }
-
- @Override
- public String part() {
- return "splitting of file '" + super.part() + "'";
- }
- }
-
- @Keep
- public static final class Options {
- private final DiagnosticsHandler diagnosticsHandler;
- private List<String> inputArchives = new ArrayList<>();
- private List<FeatureJar> featureJars = new ArrayList<>();
- private List<String> baseJars = new ArrayList<>();
- private String baseOutputName = DEFAULT_BASE_NAME;
- private String output = DEFAULT_OUTPUT_DIR;
- private String featureSplitMapping;
- private String proguardMap;
- private String mainDexList;
- private boolean splitNonClassResources = false;
-
- public Options() {
- this(new DiagnosticsHandler() {});
- }
-
- public Options(DiagnosticsHandler diagnosticsHandler) {
- this.diagnosticsHandler = diagnosticsHandler;
- }
-
- public DiagnosticsHandler getDiagnosticsHandler() {
- return diagnosticsHandler;
- }
-
- public String getMainDexList() {
- return mainDexList;
- }
-
- public void setMainDexList(String mainDexList) {
- this.mainDexList = mainDexList;
- }
-
- public String getOutput() {
- return output;
- }
-
- public void setOutput(String output) {
- this.output = output;
- }
-
- public String getFeatureSplitMapping() {
- return featureSplitMapping;
- }
-
- public void setFeatureSplitMapping(String featureSplitMapping) {
- this.featureSplitMapping = featureSplitMapping;
- }
-
- public String getProguardMap() {
- return proguardMap;
- }
-
- public void setProguardMap(String proguardMap) {
- this.proguardMap = proguardMap;
- }
-
- public String getBaseOutputName() {
- return baseOutputName;
- }
-
- public void setBaseOutputName(String baseOutputName) {
- this.baseOutputName = baseOutputName;
- }
-
- public void addInputArchive(String inputArchive) {
- inputArchives.add(inputArchive);
- }
-
- public void addBaseJar(String baseJar) {
- baseJars.add(baseJar);
- }
-
- private void addFeatureJar(FeatureJar featureJar) {
- featureJars.add(featureJar);
- }
-
- public void addFeatureJar(String jar) {
- featureJars.add(new FeatureJar(jar));
- }
-
- public void addFeatureJar(String jar, String outputName) {
- featureJars.add(new FeatureJar(jar, outputName));
- }
-
- public void setSplitNonClassResources(boolean value) {
- splitNonClassResources = value;
- }
-
- public ImmutableList<String> getInputArchives() {
- return ImmutableList.copyOf(inputArchives);
- }
-
- ImmutableList<FeatureJar> getFeatureJars() {
- return ImmutableList.copyOf(featureJars);
- }
-
- ImmutableList<String> getBaseJars() {
- return ImmutableList.copyOf(baseJars);
- }
-
- // Shorthand error messages.
- public Diagnostic error(String msg) {
- StringDiagnostic error = new StringDiagnostic(msg);
- diagnosticsHandler.error(error);
- return error;
- }
- }
-
- /**
- * Parse a feature jar argument and return the corresponding FeatureJar representation.
- * Default to use the name of the jar file if the argument contains no ':', if the argument
- * contains ':', then use the value after the ':' as the name.
- * @param argument
- */
- private static FeatureJar parseFeatureJarArgument(String argument) {
- if (argument.contains(":")) {
- String[] parts = argument.split(":");
- if (parts.length > 2) {
- throw new RuntimeException("--feature-jar argument contains more than one :");
- }
- return new FeatureJar(parts[0], parts[1]);
- }
- return new FeatureJar(argument);
- }
-
- private static Options parseArguments(String[] args) {
- Options options = new Options();
- ParseContext context = new ParseContext(args);
- while (context.head() != null) {
- List<String> inputs = OptionsParsing.tryParseMulti(context, "--input");
- if (inputs != null) {
- inputs.forEach(options::addInputArchive);
- continue;
- }
- List<String> featureJars = OptionsParsing.tryParseMulti(context, "--feature-jar");
- if (featureJars != null) {
- featureJars.forEach((feature) -> options.addFeatureJar(parseFeatureJarArgument(feature)));
- continue;
- }
- List<String> baseJars = OptionsParsing.tryParseMulti(context, "--base-jar");
- if (baseJars != null) {
- baseJars.forEach(options::addBaseJar);
- continue;
- }
- String output = OptionsParsing.tryParseSingle(context, "--output", "-o");
- if (output != null) {
- options.setOutput(output);
- continue;
- }
-
- String mainDexList= OptionsParsing.tryParseSingle(context, "--main-dex-list", null);
- if (mainDexList!= null) {
- options.setMainDexList(mainDexList);
- continue;
- }
-
- String proguardMap = OptionsParsing.tryParseSingle(context, "--proguard-map", null);
- if (proguardMap != null) {
- options.setProguardMap(proguardMap);
- continue;
- }
- String baseOutputName = OptionsParsing.tryParseSingle(context, "--base-output-name", null);
- if (baseOutputName != null) {
- options.setBaseOutputName(baseOutputName);
- continue;
- }
- String featureSplit = OptionsParsing.tryParseSingle(context, "--feature-splits", null);
- if (featureSplit != null) {
- options.setFeatureSplitMapping(featureSplit);
- continue;
- }
- Boolean b = OptionsParsing.tryParseBoolean(context, "--split-non-class-resources");
- if (b != null) {
- options.setSplitNonClassResources(b);
- continue;
- }
- throw new RuntimeException(String.format("Unknown options: '%s'.", context.head()));
- }
- return options;
- }
-
- private static FeatureClassMapping createFeatureClassMapping(Options options)
- throws FeatureMappingException {
- if (options.getFeatureSplitMapping() != null) {
- return FeatureClassMapping.fromSpecification(
- Paths.get(options.getFeatureSplitMapping()), options.getDiagnosticsHandler());
- }
- assert !options.getFeatureJars().isEmpty();
- return FeatureClassMapping.Internal.fromJarFiles(options.getFeatureJars(),
- options.getBaseJars(), options.getBaseOutputName(), options.getDiagnosticsHandler());
- }
-
- private static void run(String[] args)
- throws CompilationFailedException, FeatureMappingException {
- Options options = parseArguments(args);
- run(options);
- }
-
- public static void run(Options options)
- throws FeatureMappingException, CompilationFailedException {
- Diagnostic error = null;
- if (options.getInputArchives().isEmpty()) {
- error = options.error("Need at least one --input");
- }
- if (options.getFeatureSplitMapping() == null && options.getFeatureJars().isEmpty()) {
- error = options.error("You must supply a feature split mapping or feature jars");
- }
- if (options.getFeatureSplitMapping() != null && !options.getFeatureJars().isEmpty()) {
- error = options.error("You can't supply both a feature split mapping and feature jars");
- }
- if (error != null) {
- throw new AbortException(error);
- }
-
- D8Command.Builder builder = D8Command.builder(options.diagnosticsHandler);
-
-
- for (String s : options.inputArchives) {
- builder.addProgramFiles(Paths.get(s));
- }
- // We set the actual consumer on the ApplicationWriter when we have calculated the distribution
- // since we don't yet know the distribution.
- builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
- if (options.getMainDexList() != null) {
- builder.addMainDexListFiles(Paths.get(options.getMainDexList()));
- }
-
- FeatureClassMapping featureClassMapping = createFeatureClassMapping(options);
-
- DexSplitterHelper.run(
- builder.build(), featureClassMapping, options.getOutput(), options.getProguardMap());
-
- if (options.splitNonClassResources) {
- splitNonClassResources(options, featureClassMapping);
- }
- }
-
- private static void splitNonClassResources(Options options,
- FeatureClassMapping featureClassMapping) {
- for (String s : options.inputArchives) {
- try (ZipFile zipFile = new ZipFile(s, StandardCharsets.UTF_8)) {
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- String name = entry.getName();
- if (!ZipUtils.isDexFile(name) && !ZipUtils.isClassFile(name)) {
- String feature = featureClassMapping.featureForNonClass(name);
- Path outputDir = Paths.get(options.getOutput()).resolve(feature);
- try (InputStream stream = zipFile.getInputStream(entry)) {
- Path outputFile = outputDir.resolve(name);
- Path parent = outputFile.getParent();
- if (parent != null) {
- Files.createDirectories(parent);
- }
- Files.copy(stream, outputFile);
- }
- }
- }
- } catch (IOException e) {
- ExceptionDiagnostic error = new ExceptionDiagnostic(e, new ZipFileOrigin(Paths.get(s)));
- options.getDiagnosticsHandler().error(error);
- throw new AbortException(error);
- }
- }
- }
-
- public static void main(String[] args) {
- if (PRINT_ARGS) {
- printArgs(args);
- }
- ExceptionUtils.withMainProgramHandler(
- () -> {
- try {
- run(args);
- } catch (FeatureMappingException e) {
- // TODO(ricow): Report feature mapping errors via the reporter.
- throw new RuntimeException("Splitting failed: " + e.getMessage());
- }
- });
- }
-
- private static void printArgs(String[] args) {
- System.err.printf("r8.DexSplitter");
- for (String s : args) {
- System.err.printf(" %s", s);
- }
- System.err.println("");
- }
-}
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 81979c8..e5e4459 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -592,7 +592,7 @@
// TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod().
public DexEncodedMethod lookupStaticTarget(DexMethod method, DexProgramClass context) {
assert checkIfObsolete();
- return unsafeResolveMethodDueToDexFormat(method).lookupInvokeStaticTarget(context, this);
+ return unsafeResolveMethodDueToDexFormatLegacy(method).lookupInvokeStaticTarget(context, this);
}
// TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod().
@@ -613,7 +613,7 @@
// TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod().
public DexClassAndMethod lookupSuperTarget(DexMethod method, DexProgramClass context) {
assert checkIfObsolete();
- return unsafeResolveMethodDueToDexFormat(method).lookupInvokeSuperTarget(context, this);
+ return unsafeResolveMethodDueToDexFormatLegacy(method).lookupInvokeSuperTarget(context, this);
}
// TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod().
@@ -632,7 +632,7 @@
// TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod().
public DexEncodedMethod lookupDirectTarget(DexMethod method, DexProgramClass context) {
assert checkIfObsolete();
- return unsafeResolveMethodDueToDexFormat(method).lookupInvokeDirectTarget(context, this);
+ return unsafeResolveMethodDueToDexFormatLegacy(method).lookupInvokeDirectTarget(context, this);
}
// TODO(b/155968472): This should take a parameter `boolean isInterface` and use resolveMethod().
@@ -646,32 +646,129 @@
* <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the
* kind of a method reference.
*/
- public MethodResolutionResult unsafeResolveMethodDueToDexFormat(DexMethod method) {
+ public MethodResolutionResult unsafeResolveMethodDueToDexFormatLegacy(DexMethod method) {
assert checkIfObsolete();
return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
.unsafeResolveMethodDueToDexFormat(method);
}
+ public MethodResolutionResult resolveMethodLegacy(DexMethod invokedMethod, boolean isInterface) {
+ assert checkIfObsolete();
+ return resolveMethodOnLegacy(invokedMethod.getHolderType(), invokedMethod, isInterface);
+ }
+
+ public MethodResolutionResult resolveMethodOnLegacy(DexClass clazz, DexMethod method) {
+ assert checkIfObsolete();
+ return clazz.isInterface()
+ ? resolveMethodOnInterfaceLegacy(clazz, method)
+ : resolveMethodOnClassLegacy(clazz, method);
+ }
+
+ public MethodResolutionResult resolveMethodOnLegacy(
+ DexClass clazz, DexMethodSignature methodSignature) {
+ assert checkIfObsolete();
+ return clazz.isInterface()
+ ? resolveMethodOnInterfaceLegacy(clazz, methodSignature)
+ : resolveMethodOnClassLegacy(clazz, methodSignature);
+ }
+
+ public MethodResolutionResult resolveMethodOnLegacy(
+ DexType holder, DexMethod method, boolean isInterface) {
+ assert checkIfObsolete();
+ return isInterface
+ ? resolveMethodOnInterfaceLegacy(holder, method)
+ : resolveMethodOnClassLegacy(holder, method);
+ }
+
+ public MethodResolutionResult resolveMethodOnClassHolderLegacy(DexMethod method) {
+ assert checkIfObsolete();
+ return resolveMethodOnClassLegacy(method.getHolderType(), method);
+ }
+
+ public MethodResolutionResult resolveMethodOnClassLegacy(DexType holder, DexMethod method) {
+ assert checkIfObsolete();
+ return resolveMethodOnClassLegacy(holder, method.getProto(), method.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnClassLegacy(
+ DexType holder, DexMethodSignature signature) {
+ assert checkIfObsolete();
+ return resolveMethodOnClassLegacy(holder, signature.getProto(), signature.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnClassLegacy(
+ DexType holder, DexProto proto, DexString name) {
+ assert checkIfObsolete();
+ return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ .resolveMethodOnClass(holder, proto, name);
+ }
+
+ public MethodResolutionResult resolveMethodOnClassLegacy(DexClass clazz, DexMethod method) {
+ assert checkIfObsolete();
+ return resolveMethodOnClassLegacy(clazz, method.getProto(), method.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnClassLegacy(
+ DexClass clazz, DexMethodSignature signature) {
+ assert checkIfObsolete();
+ return resolveMethodOnClassLegacy(clazz, signature.getProto(), signature.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnClassLegacy(
+ DexClass clazz, DexProto proto, DexString name) {
+ assert checkIfObsolete();
+ return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ .resolveMethodOnClass(clazz, proto, name);
+ }
+
+ public MethodResolutionResult resolveMethodOnInterfaceHolderLegacy(DexMethod method) {
+ assert checkIfObsolete();
+ return resolveMethodOnInterfaceLegacy(method.getHolderType(), method);
+ }
+
+ public MethodResolutionResult resolveMethodOnInterfaceLegacy(DexType holder, DexMethod method) {
+ assert checkIfObsolete();
+ return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ .resolveMethodOnInterface(holder, method.getProto(), method.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnInterfaceLegacy(DexClass clazz, DexMethod method) {
+ assert checkIfObsolete();
+ return resolveMethodOnInterfaceLegacy(clazz, method.getProto(), method.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnInterfaceLegacy(
+ DexClass clazz, DexMethodSignature methodSignature) {
+ assert checkIfObsolete();
+ return resolveMethodOnInterfaceLegacy(
+ clazz, methodSignature.getProto(), methodSignature.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnInterfaceLegacy(
+ DexClass clazz, DexProto proto, DexString name) {
+ assert checkIfObsolete();
+ return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ .resolveMethodOnInterface(clazz, proto, name);
+ }
+
+ /**
+ * This method will query the definition of the holder to decide on which resolution to use.
+ *
+ * <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the
+ * kind of a method reference.
+ */
+ public MethodResolutionResult unsafeResolveMethodDueToDexFormat(DexMethod method) {
+ assert checkIfObsolete();
+ return MethodResolution.create(
+ this::contextIndependentDefinitionForWithResolutionResult, dexItemFactory())
+ .unsafeResolveMethodDueToDexFormat(method);
+ }
+
public MethodResolutionResult resolveMethod(DexMethod invokedMethod, boolean isInterface) {
assert checkIfObsolete();
return resolveMethodOn(invokedMethod.getHolderType(), invokedMethod, isInterface);
}
- public MethodResolutionResult resolveMethodOn(DexClass clazz, DexMethod method) {
- assert checkIfObsolete();
- return clazz.isInterface()
- ? resolveMethodOnInterface(clazz, method)
- : resolveMethodOnClass(clazz, method);
- }
-
- public MethodResolutionResult resolveMethodOn(
- DexClass clazz, DexMethodSignature methodSignature) {
- assert checkIfObsolete();
- return clazz.isInterface()
- ? resolveMethodOnInterface(clazz, methodSignature)
- : resolveMethodOnClass(clazz, methodSignature);
- }
-
public MethodResolutionResult resolveMethodOn(
DexType holder, DexMethod method, boolean isInterface) {
assert checkIfObsolete();
@@ -698,7 +795,8 @@
public MethodResolutionResult resolveMethodOnClass(
DexType holder, DexProto proto, DexString name) {
assert checkIfObsolete();
- return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ return MethodResolution.create(
+ this::contextIndependentDefinitionForWithResolutionResult, dexItemFactory())
.resolveMethodOnClass(holder, proto, name);
}
@@ -715,7 +813,8 @@
public MethodResolutionResult resolveMethodOnClass(
DexClass clazz, DexProto proto, DexString name) {
assert checkIfObsolete();
- return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ return MethodResolution.create(
+ this::contextIndependentDefinitionForWithResolutionResult, dexItemFactory())
.resolveMethodOnClass(clazz, proto, name);
}
@@ -726,7 +825,8 @@
public MethodResolutionResult resolveMethodOnInterface(DexType holder, DexMethod method) {
assert checkIfObsolete();
- return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ return MethodResolution.create(
+ this::contextIndependentDefinitionForWithResolutionResult, dexItemFactory())
.resolveMethodOnInterface(holder, method.getProto(), method.getName());
}
@@ -744,7 +844,8 @@
public MethodResolutionResult resolveMethodOnInterface(
DexClass clazz, DexProto proto, DexString name) {
assert checkIfObsolete();
- return MethodResolution.createLegacy(this::definitionFor, dexItemFactory())
+ return MethodResolution.create(
+ this::contextIndependentDefinitionForWithResolutionResult, dexItemFactory())
.resolveMethodOnInterface(clazz, proto, name);
}
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 4974a5d..8797a80 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -27,7 +27,6 @@
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
@@ -62,7 +61,6 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
-import java.util.function.BiPredicate;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -957,12 +955,7 @@
}
CfFrameVerificationHelper builder =
new CfFrameVerificationHelper(
- previousMethodSignature.getHolderType(),
- stateMap,
- tryCatchRanges,
- isAssignablePredicate(appView),
- appView.dexItemFactory(),
- maxStack);
+ appView, previousMethodSignature.getHolderType(), stateMap, tryCatchRanges, maxStack);
for (CfTryCatch tryCatchRange : tryCatchRanges) {
try {
builder.checkTryCatchRange(tryCatchRange);
@@ -1080,47 +1073,4 @@
}
return initialLocals;
}
-
- private BiPredicate<DexType, DexType> isAssignablePredicate(AppView<?> appView) {
- return (source, target) -> isAssignable(source, target, appView);
- }
-
- // Rules found at https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.2
- private boolean isAssignable(DexType source, DexType target, AppView<?> appView) {
- DexItemFactory factory = appView.dexItemFactory();
- source = byteCharShortOrBooleanToInt(source, factory);
- target = byteCharShortOrBooleanToInt(target, factory);
- if (source == target) {
- return true;
- }
- if (source.isPrimitiveType() || target.isPrimitiveType()) {
- return false;
- }
- // Both are now references - everything is assignable to object.
- if (target == factory.objectType) {
- return true;
- }
- // isAssignable(null, class(_, _)).
- // isAssignable(null, arrayOf(_)).
- if (source == DexItemFactory.nullValueType) {
- return true;
- }
- if (target.isArrayType() != target.isArrayType()) {
- return false;
- }
- if (target.isArrayType()) {
- return isAssignable(
- target.toArrayElementType(factory), target.toArrayElementType(factory), appView);
- }
- // TODO(b/166570659): Do a sub-type check that allows for missing classes in hierarchy.
- return MemberType.fromDexType(source) == MemberType.fromDexType(target);
- }
-
- private DexType byteCharShortOrBooleanToInt(DexType type, DexItemFactory factory) {
- // byte, char, short and boolean has verification type int.
- if (type.isByteType() || type.isCharType() || type.isShortType() || type.isBooleanType()) {
- return factory.intType;
- }
- return type;
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolution.java b/src/main/java/com/android/tools/r8/graph/MethodResolution.java
index 0927de2..a680b25 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolution.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolution.java
@@ -52,6 +52,11 @@
false);
}
+ public static MethodResolution create(
+ Function<DexType, ClassResolutionResult> definitionFor, DexItemFactory factory) {
+ return new MethodResolution(definitionFor, factory, true);
+ }
+
private ClassResolutionResult definitionFor(DexType type) {
return definitionFor.apply(type);
}
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 6c8703b..6abb160 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -60,7 +60,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(group.getSuperType(), template)
+ .resolveMethodOnClassLegacy(group.getSuperType(), template)
.asSingleResolution();
if (resolutionResult == null || resolutionResult.getResolvedMethod().isAbstract()) {
// If there is no super method or the method is abstract it should not be called.
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
index fa9bbde..9856e0b 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
@@ -487,7 +487,7 @@
DexMethod rewrittenMethod =
appView.graphLens().lookupInvokeDirect(method, getContext()).getReference();
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClassHolder(rewrittenMethod);
+ appView.appInfo().resolveMethodOnClassHolderLegacy(rewrittenMethod);
if (resolutionResult.isSingleResolution()
&& resolutionResult.getResolvedHolder().isProgramClass()) {
enqueueMethod(resolutionResult.getResolvedProgramMethod());
@@ -499,7 +499,10 @@
DexMethod rewrittenMethod =
appView.graphLens().lookupInvokeInterface(method, getContext()).getReference();
DexClassAndMethod resolvedMethod =
- appView.appInfo().resolveMethodOnInterfaceHolder(rewrittenMethod).getResolutionPair();
+ appView
+ .appInfo()
+ .resolveMethodOnInterfaceHolderLegacy(rewrittenMethod)
+ .getResolutionPair();
if (resolvedMethod != null) {
fail();
}
@@ -512,7 +515,7 @@
ProgramMethod resolvedMethod =
appView
.appInfo()
- .unsafeResolveMethodDueToDexFormat(rewrittenMethod)
+ .unsafeResolveMethodDueToDexFormatLegacy(rewrittenMethod)
.getResolvedProgramMethod();
if (resolvedMethod != null) {
triggerClassInitializerIfNotAlreadyTriggeredInContext(resolvedMethod.getHolder());
@@ -537,7 +540,7 @@
DexMethod rewrittenMethod =
appView.graphLens().lookupInvokeVirtual(method, getContext()).getReference();
DexClassAndMethod resolvedMethod =
- appView.appInfo().resolveMethodOnClassHolder(rewrittenMethod).getResolutionPair();
+ appView.appInfo().resolveMethodOnClassHolderLegacy(rewrittenMethod).getResolutionPair();
if (resolvedMethod != null) {
if (!resolvedMethod.getHolder().isEffectivelyFinal(appView)) {
fail();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
index fecb888..07b2fc7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
@@ -108,7 +108,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(superType, method.getReference())
+ .resolveMethodOnClassLegacy(superType, method.getReference())
.asSingleResolution();
return resolutionResult != null && !resolutionResult.getResolvedMethod().isAbstract();
}
@@ -121,7 +121,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOnInterface(interfaceType, method.getReference())
+ .resolveMethodOnInterfaceLegacy(interfaceType, method.getReference())
.asSingleResolution();
return resolutionResult != null && !resolutionResult.getResolvedMethod().isAbstract();
});
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java
index ca52f7c..2a3602c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java
@@ -171,7 +171,7 @@
if (clazzReserved.contains(signature)) {
DexMethod template = signature.withHolder(clazz, appView.dexItemFactory());
SingleResolutionResult<?> result =
- appView.appInfo().resolveMethodOnClass(clazz, template).asSingleResolution();
+ appView.appInfo().resolveMethodOnClassLegacy(clazz, template).asSingleResolution();
if (result == null || result.getResolvedHolder().isInterface()) {
category = MethodCategory.KEEP_ABSENT;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/deadlock/SingleCallerInformation.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/deadlock/SingleCallerInformation.java
index 95f0385..bbf486f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/deadlock/SingleCallerInformation.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/deadlock/SingleCallerInformation.java
@@ -216,7 +216,7 @@
ProgramMethod target =
appView
.appInfo()
- .unsafeResolveMethodDueToDexFormat(rewrittenMethod)
+ .unsafeResolveMethodDueToDexFormatLegacy(rewrittenMethod)
.getResolvedProgramMethod();
if (target != null) {
recordDispatchTarget(target);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
index 670f74a..9a7ddd8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
@@ -333,7 +333,7 @@
}
DexMethod method = instruction.getInvokedMethod();
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnInterface(method.holder, method);
+ appView.appInfo().resolveMethodOnInterfaceLegacy(method.holder, method);
if (!resolutionResult.isSingleResolution()) {
return false;
}
@@ -394,7 +394,7 @@
return false;
}
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOn(superType, method, instruction.isInterface);
+ appView.appInfo().resolveMethodOnLegacy(superType, method, instruction.isInterface);
if (!resolutionResult.isSingleResolution()) {
return false;
}
@@ -431,7 +431,7 @@
}
DexMethod method = instruction.getInvokedMethod();
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(method.holder, method);
+ appView.appInfo().resolveMethodOnClassLegacy(method.holder, method);
if (!resolutionResult.isSingleResolution()) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
index 5710f6e..a6150bc 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
@@ -5,38 +5,155 @@
package com.android.tools.r8.ir.analysis.framework.intraprocedural;
import com.android.tools.r8.utils.TraversalContinuation;
-import com.google.common.collect.Iterables;
-import java.util.Collection;
+import com.android.tools.r8.utils.TraversalUtils;
import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
public interface ControlFlowGraph<Block, Instruction> {
- Collection<Block> getPredecessors(Block block);
-
- Collection<Block> getSuccessors(Block block);
-
default boolean hasUniquePredecessor(Block block) {
- return getPredecessors(block).size() == 1;
- }
-
- default Block getUniquePredecessor(Block block) {
- assert hasUniquePredecessor(block);
- return Iterables.getOnlyElement(getPredecessors(block));
+ return TraversalUtils.isSingleton(counter -> traversePredecessors(block, counter));
}
default boolean hasUniqueSuccessor(Block block) {
- return getSuccessors(block).size() == 1;
+ return TraversalUtils.isSingleton(counter -> traverseSuccessors(block, counter));
}
default boolean hasUniqueSuccessorWithUniquePredecessor(Block block) {
- return hasUniqueSuccessor(block) && getPredecessors(getUniqueSuccessor(block)).size() == 1;
+ return hasUniqueSuccessor(block) && hasUniquePredecessor(getUniqueSuccessor(block));
}
default Block getUniqueSuccessor(Block block) {
assert hasUniqueSuccessor(block);
- return Iterables.getOnlyElement(getSuccessors(block));
+ return TraversalUtils.getFirst(collector -> traverseSuccessors(block, collector));
}
+ // Block traversal.
+
+ default <BT, CT> TraversalContinuation<BT, CT> traversePredecessors(
+ Block block, Function<? super Block, TraversalContinuation<BT, CT>> fn) {
+ return traversePredecessors(block, (predecessor, ignore) -> fn.apply(predecessor), null);
+ }
+
+ default <BT, CT> TraversalContinuation<BT, CT> traverseNormalPredecessors(
+ Block block, Function<? super Block, TraversalContinuation<BT, CT>> fn) {
+ return traverseNormalPredecessors(block, (predecessor, ignore) -> fn.apply(predecessor), null);
+ }
+
+ default <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalPredecessors(
+ Block block, Function<? super Block, TraversalContinuation<BT, CT>> fn) {
+ return traverseExceptionalPredecessors(
+ block, (predecessor, ignore) -> fn.apply(predecessor), null);
+ }
+
+ default <BT, CT> TraversalContinuation<BT, CT> traverseSuccessors(
+ Block block, Function<? super Block, TraversalContinuation<BT, CT>> fn) {
+ return traverseSuccessors(block, (successor, ignore) -> fn.apply(successor), null);
+ }
+
+ default <BT, CT> TraversalContinuation<BT, CT> traverseNormalSuccessors(
+ Block block, Function<? super Block, TraversalContinuation<BT, CT>> fn) {
+ return traverseNormalSuccessors(block, (successor, ignore) -> fn.apply(successor), null);
+ }
+
+ default <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
+ Block block, Function<? super Block, TraversalContinuation<BT, CT>> fn) {
+ return traverseExceptionalSuccessors(block, (successor, ignore) -> fn.apply(successor), null);
+ }
+
+ // Block traversal with result.
+
+ default <BT, CT> TraversalContinuation<BT, CT> traversePredecessors(
+ Block block,
+ BiFunction<? super Block, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return traverseNormalPredecessors(block, fn, initialValue)
+ .ifContinueThen(
+ continuation ->
+ traverseExceptionalPredecessors(block, fn, continuation.getValueOrDefault(null)));
+ }
+
+ <BT, CT> TraversalContinuation<BT, CT> traverseNormalPredecessors(
+ Block block,
+ BiFunction<? super Block, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue);
+
+ <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalPredecessors(
+ Block block,
+ BiFunction<? super Block, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue);
+
+ default <BT, CT> TraversalContinuation<BT, CT> traverseSuccessors(
+ Block block,
+ BiFunction<? super Block, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return traverseNormalSuccessors(block, fn, initialValue)
+ .ifContinueThen(
+ continuation ->
+ traverseExceptionalSuccessors(block, fn, continuation.getValueOrDefault(null)));
+ }
+
+ <BT, CT> TraversalContinuation<BT, CT> traverseNormalSuccessors(
+ Block block,
+ BiFunction<? super Block, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue);
+
+ <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
+ Block block,
+ BiFunction<? super Block, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue);
+
+ // Block iteration.
+
+ default void forEachPredecessor(Block block, Consumer<Block> consumer) {
+ forEachNormalPredecessor(block, consumer);
+ forEachExceptionalPredecessor(block, consumer);
+ }
+
+ default void forEachNormalPredecessor(Block block, Consumer<Block> consumer) {
+ traverseNormalPredecessors(
+ block,
+ predecessor -> {
+ consumer.accept(predecessor);
+ return TraversalContinuation.doContinue();
+ });
+ }
+
+ default void forEachExceptionalPredecessor(Block block, Consumer<Block> consumer) {
+ traverseExceptionalPredecessors(
+ block,
+ exceptionalPredecessor -> {
+ consumer.accept(exceptionalPredecessor);
+ return TraversalContinuation.doContinue();
+ });
+ }
+
+ default void forEachSuccessor(Block block, Consumer<Block> consumer) {
+ forEachNormalSuccessor(block, consumer);
+ forEachExceptionalSuccessor(block, consumer);
+ }
+
+ default void forEachNormalSuccessor(Block block, Consumer<Block> consumer) {
+ traverseNormalSuccessors(
+ block,
+ successor -> {
+ consumer.accept(successor);
+ return TraversalContinuation.doContinue();
+ });
+ }
+
+ default void forEachExceptionalSuccessor(Block block, Consumer<Block> consumer) {
+ traverseExceptionalSuccessors(
+ block,
+ exceptionalSuccessor -> {
+ consumer.accept(exceptionalSuccessor);
+ return TraversalContinuation.doContinue();
+ });
+ }
+
+ // Instruction traversal.
+
<BT, CT> TraversalContinuation<BT, CT> traverseInstructions(
Block block, BiFunction<Instruction, CT, TraversalContinuation<BT, CT>> fn, CT initialValue);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IRControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IRControlFlowGraph.java
new file mode 100644
index 0000000..aae27f7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IRControlFlowGraph.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.analysis.framework.intraprocedural;
+
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.Instruction;
+
+public interface IRControlFlowGraph extends ControlFlowGraph<BasicBlock, Instruction> {
+
+ @Override
+ default boolean hasUniquePredecessor(BasicBlock block) {
+ return block.hasUniquePredecessor();
+ }
+
+ @Override
+ default boolean hasUniqueSuccessor(BasicBlock block) {
+ return block.hasUniqueSuccessor();
+ }
+
+ @Override
+ default boolean hasUniqueSuccessorWithUniquePredecessor(BasicBlock block) {
+ return block.hasUniqueSuccessorWithUniquePredecessor();
+ }
+
+ @Override
+ default BasicBlock getUniqueSuccessor(BasicBlock block) {
+ return block.getUniqueSuccessor();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
index 969197f..f904da3 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.ir.analysis.framework.intraprocedural.DataflowAnalysisResult.SuccessfulDataflowAnalysisResult;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.TraversalContinuation;
+import com.android.tools.r8.utils.TraversalUtils;
import com.android.tools.r8.utils.WorkList;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -100,7 +101,7 @@
// Update the block exit state, and re-enqueue all successor blocks if the abstract state
// changed.
if (setBlockExitState(end, state)) {
- worklist.addAllIgnoringSeenSet(cfg.getSuccessors(end));
+ cfg.forEachSuccessor(end, worklist::addIgnoringSeenSet);
}
// Add the computed exit state to the entry state of each successor that satisfies the
@@ -114,14 +115,17 @@
if (shouldCacheBlockEntryStateFor(block)) {
return blockEntryStatesCache.getOrDefault(block, bottom);
}
- StateType result = bottom;
- for (Block predecessor : cfg.getPredecessors(block)) {
- StateType edgeState =
- transfer.computeBlockEntryState(
- block, predecessor, blockExitStates.getOrDefault(predecessor, bottom));
- result = result.join(edgeState);
- }
- return result;
+ TraversalContinuation<?, StateType> traversalContinuation =
+ cfg.traversePredecessors(
+ block,
+ (predecessor, entryState) -> {
+ StateType edgeState =
+ transfer.computeBlockEntryState(
+ block, predecessor, blockExitStates.getOrDefault(predecessor, bottom));
+ return TraversalContinuation.doContinue(entryState.join(edgeState));
+ },
+ bottom);
+ return traversalContinuation.asContinue().getValue();
}
boolean setBlockExitState(Block block, StateType state) {
@@ -132,16 +136,18 @@
}
void updateBlockEntryStateCacheForSuccessors(Block block, StateType state) {
- for (Block successor : cfg.getSuccessors(block)) {
- if (shouldCacheBlockEntryStateFor(successor)) {
- StateType edgeState = transfer.computeBlockEntryState(successor, block, state);
- StateType previous = blockEntryStatesCache.getOrDefault(successor, bottom);
- blockEntryStatesCache.put(successor, previous.join(edgeState));
- }
- }
+ cfg.forEachSuccessor(
+ block,
+ successor -> {
+ if (shouldCacheBlockEntryStateFor(successor)) {
+ StateType edgeState = transfer.computeBlockEntryState(successor, block, state);
+ StateType previous = blockEntryStatesCache.getOrDefault(successor, bottom);
+ blockEntryStatesCache.put(successor, previous.join(edgeState));
+ }
+ });
}
boolean shouldCacheBlockEntryStateFor(Block block) {
- return cfg.getPredecessors(block).size() > 2;
+ return TraversalUtils.isSizeGreaterThan(counter -> cfg.traversePredecessors(block, counter), 2);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
index 13a9c42..789a2cb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
@@ -17,4 +17,9 @@
AbstractTransferFunction<BasicBlock, Instruction, StateType> transfer) {
super(bottom, code, transfer);
}
+
+ @Override
+ boolean shouldCacheBlockEntryStateFor(BasicBlock block) {
+ return block.getPredecessors().size() > 2;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
new file mode 100644
index 0000000..b86915c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.analysis.framework.intraprocedural.cf;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.utils.SetUtils;
+import java.util.ArrayList;
+import java.util.List;
+
+/** A basic block for {@link com.android.tools.r8.graph.CfCode}. */
+public class CfBlock {
+
+ // The CfCode instruction index of the block's first instruction.
+ int firstInstructionIndex = -1;
+
+ // The CfCode instruction index of the block's last instruction.
+ int lastInstructionIndex = -1;
+
+ // The predecessors of the block. These are stored explicitly (unlike the successors) since they
+ // cannot efficiently be computed from the block.
+ final List<CfBlock> predecessors = new ArrayList<>();
+
+ // The exceptional predecessors of the block.
+ final List<CfBlock> exceptionalPredecessors = new ArrayList<>();
+
+ // The exceptional successors of the block (i.e., the catch handlers of the block).
+ final List<CfBlock> exceptionalSuccessors = new ArrayList<>();
+
+ public CfInstruction getFallthroughInstruction(CfCode code) {
+ int fallthroughInstructionIndex = getLastInstructionIndex() + 1;
+ return fallthroughInstructionIndex < code.getInstructions().size()
+ ? code.getInstructions().get(fallthroughInstructionIndex)
+ : null;
+ }
+
+ public int getFirstInstructionIndex() {
+ return firstInstructionIndex;
+ }
+
+ public CfInstruction getLastInstruction(CfCode code) {
+ return code.getInstructions().get(lastInstructionIndex);
+ }
+
+ public int getLastInstructionIndex() {
+ return lastInstructionIndex;
+ }
+
+ public List<CfBlock> getPredecessors() {
+ return predecessors;
+ }
+
+ // TODO(b/214496607): This currently only encodes the graph, but we likely need to include the
+ // guard types here.
+ public List<CfBlock> getExceptionalPredecessors() {
+ return exceptionalPredecessors;
+ }
+
+ // TODO(b/214496607): This currently only encodes the graph, but we likely need to include the
+ // guard types here.
+ public List<CfBlock> getExceptionalSuccessors() {
+ return exceptionalSuccessors;
+ }
+
+ // A mutable interface for block construction.
+ static class MutableCfBlock extends CfBlock {
+
+ void addPredecessor(CfBlock block) {
+ predecessors.add(block);
+ }
+
+ void addExceptionalPredecessor(CfBlock block) {
+ exceptionalPredecessors.add(block);
+ }
+
+ void addExceptionalSuccessor(CfBlock block) {
+ exceptionalSuccessors.add(block);
+ }
+
+ void setFirstInstructionIndex(int firstInstructionIndex) {
+ this.firstInstructionIndex = firstInstructionIndex;
+ }
+
+ void setLastInstructionIndex(int lastInstructionIndex) {
+ this.lastInstructionIndex = lastInstructionIndex;
+ }
+
+ boolean validate() {
+ assert 0 <= firstInstructionIndex;
+ assert firstInstructionIndex <= lastInstructionIndex;
+ assert SetUtils.newIdentityHashSet(predecessors).size() == predecessors.size();
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
new file mode 100644
index 0000000..4cf9e5e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
@@ -0,0 +1,312 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.analysis.framework.intraprocedural.cf;
+
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.ControlFlowGraph;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfBlock.MutableCfBlock;
+import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.TraversalContinuation;
+import com.android.tools.r8.utils.TraversalUtils;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+
+/**
+ * The following provides a control flow graph for a piece of {@link CfCode}.
+ *
+ * <p>In the {@link CfControlFlowGraph}, each instruction that is the target of a jump (including
+ * fallthrough targets following jumps) starts a new basic block. The first instruction in {@link
+ * CfCode} also starts a new block.
+ *
+ * <p>Each block is identified by the first instruction of the block.
+ */
+public class CfControlFlowGraph implements ControlFlowGraph<CfBlock, CfInstruction> {
+
+ // Mapping from block entry instructions to cf blocks.
+ private final Map<CfInstruction, ? extends CfBlock> blocks;
+ private final CfCode code;
+
+ private CfControlFlowGraph(Map<CfInstruction, ? extends CfBlock> blocks, CfCode code) {
+ this.blocks = blocks;
+ this.code = code;
+ }
+
+ private static Builder builder(CfCode code) {
+ return new Builder(code);
+ }
+
+ public static CfControlFlowGraph create(CfCode code) {
+ return builder(code).build();
+ }
+
+ private CfBlock getBlock(CfInstruction blockEntry) {
+ assert blocks.containsKey(blockEntry);
+ return blocks.get(blockEntry);
+ }
+
+ public CfBlock getEntryBlock() {
+ return getBlock(code.getInstructions().get(0));
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalPredecessors(
+ CfBlock block,
+ BiFunction<? super CfBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return TraversalUtils.traverseIterable(block.getPredecessors(), fn, initialValue);
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalPredecessors(
+ CfBlock block,
+ BiFunction<? super CfBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return TraversalUtils.traverseIterable(block.getExceptionalPredecessors(), fn, initialValue);
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalSuccessors(
+ CfBlock block,
+ BiFunction<? super CfBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ CfInstruction blockExit = block.getLastInstruction(code);
+ CfInstruction fallthroughInstruction = block.getFallthroughInstruction(code);
+ return blockExit.traverseNormalTargets(
+ (target, value) -> fn.apply(getBlock(target), value), fallthroughInstruction, initialValue);
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
+ CfBlock block,
+ BiFunction<? super CfBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return TraversalUtils.traverseIterable(block.getExceptionalSuccessors(), fn, initialValue);
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseInstructions(
+ CfBlock block,
+ BiFunction<CfInstruction, CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ TraversalContinuation<BT, CT> traversalContinuation =
+ TraversalContinuation.doContinue(initialValue);
+ for (int instructionIndex = block.getFirstInstructionIndex();
+ instructionIndex <= block.getLastInstructionIndex();
+ instructionIndex++) {
+ CfInstruction instruction = code.getInstructions().get(instructionIndex);
+ traversalContinuation = fn.apply(instruction, traversalContinuation.asContinue().getValue());
+ if (traversalContinuation.shouldBreak()) {
+ break;
+ }
+ }
+ return traversalContinuation;
+ }
+
+ private static class Builder {
+
+ // Mapping from block entry instructions to the block that starts at each such instruction.
+ private final Map<CfInstruction, MutableCfBlock> blocks = new IdentityHashMap<>();
+
+ private final CfCode code;
+
+ Builder(CfCode code) {
+ this.code = code;
+ }
+
+ CfControlFlowGraph build() {
+ // Perform an initial pass over the CfCode to identify all instructions that start a new
+ // block.
+ createBlocks();
+
+ // Perform a second pass over the CfCode to finalize the identified blocks. This includes
+ // setting the instruction index of the last instruction of each block, which relies on having
+ // identified all block entries up front.
+ processBlocks();
+
+ assert blocks.values().stream().allMatch(MutableCfBlock::validate);
+
+ return new CfControlFlowGraph(blocks, code);
+ }
+
+ private void createBlocks() {
+ List<CfInstruction> instructions = code.getInstructions();
+
+ // The first instruction starts the first block.
+ createBlockIfAbsent(instructions.get(0));
+
+ // Create a block for each instruction that is targeted by a jump or fallthrough.
+ for (int instructionIndex = 0; instructionIndex < instructions.size(); instructionIndex++) {
+ CfInstruction instruction = instructions.get(instructionIndex);
+ if (instruction.isJump()) {
+ int fallthroughInstructionIndex = instructionIndex + 1;
+ CfInstruction fallthroughInstruction =
+ fallthroughInstructionIndex < instructions.size()
+ ? instructions.get(fallthroughInstructionIndex)
+ : null;
+ instruction.forEachNormalTarget(this::createBlockIfAbsent, fallthroughInstruction);
+ }
+ }
+
+ for (CfTryCatch tryCatch : code.getTryCatchRanges()) {
+ // Create a new block at the beginning and end of each try range. This is needed to ensure
+ // that each block has the same set of catch handlers.
+ createBlockIfAbsent(tryCatch.getStart());
+ createBlockIfAbsent(tryCatch.getEnd());
+
+ // Create a new block for the beginning of each catch handler.
+ tryCatch.forEachTarget(this::createBlockIfAbsent);
+ }
+ }
+
+ private void processBlocks() {
+ // A collection of active catch handlers. The catch handlers are stored in a map where the key
+ // is the label at which the catch handlers end.
+ Map<CfLabel, List<CfTryCatch>> activeUntilCatchHandlers = new IdentityHashMap<>();
+
+ // A collection of inactive catch handlers. The catch handlers are stored in a map where the
+ // key is the label at which the catch handlers start.
+ Map<CfLabel, List<CfTryCatch>> inactiveUntilCatchHandlers = new IdentityHashMap<>();
+
+ // Initialize all catch handlers to be inactive.
+ for (CfTryCatch tryCatch : code.getTryCatchRanges()) {
+ inactiveUntilCatchHandlers
+ .computeIfAbsent(tryCatch.getStart(), ignoreKey(ArrayList::new))
+ .add(tryCatch);
+ }
+
+ // Process each instruction.
+ List<CfInstruction> instructions = code.getInstructions();
+ for (int instructionIndex = 0; instructionIndex < instructions.size(); instructionIndex++) {
+ CfInstruction instruction = instructions.get(instructionIndex);
+ MutableCfBlock block = getBlockOrNull(instruction);
+ if (block != null) {
+ instructionIndex =
+ processBlock(
+ instruction,
+ instructionIndex,
+ block,
+ activeUntilCatchHandlers,
+ inactiveUntilCatchHandlers);
+ }
+ }
+
+ assert activeUntilCatchHandlers.isEmpty();
+ assert inactiveUntilCatchHandlers.isEmpty();
+ }
+
+ private int processBlock(
+ CfInstruction instruction,
+ int instructionIndex,
+ MutableCfBlock block,
+ Map<CfLabel, List<CfTryCatch>> activeUntilCatchHandlers,
+ Map<CfLabel, List<CfTryCatch>> inactiveUntilCatchHandlers) {
+ // Record the index of the first instruction of the block.
+ block.setFirstInstructionIndex(instructionIndex);
+
+ if (instruction.isLabel()) {
+ updateCatchHandlers(
+ instruction.asLabel(), activeUntilCatchHandlers, inactiveUntilCatchHandlers);
+ }
+
+ // Visit each instruction belonging to the current block.
+ Set<CfLabel> exceptionalSuccessors = new LinkedHashSet<>();
+ do {
+ assert !instruction.isLabel()
+ || verifyCatchHandlersUnchanged(
+ instruction.asLabel(), activeUntilCatchHandlers, inactiveUntilCatchHandlers);
+ if (instruction.canThrow()) {
+ for (CfTryCatch tryCatch : IterableUtils.flatten(activeUntilCatchHandlers.values())) {
+ exceptionalSuccessors.addAll(tryCatch.getTargets());
+ }
+ }
+ if (isBlockExit(instructionIndex)) {
+ break;
+ }
+ instruction = code.getInstructions().get(++instructionIndex);
+ } while (true);
+
+ // Record the index of the last instruction of the block.
+ block.setLastInstructionIndex(instructionIndex);
+
+ // Add the current block as a predecessor of the successor blocks.
+ CfInstruction fallthroughInstruction = block.getFallthroughInstruction(code);
+ instruction.forEachNormalTarget(
+ target -> getBlock(target).addPredecessor(block), fallthroughInstruction);
+
+ // Add the current block as an exceptional predecessor of the exceptional successor blocks.
+ exceptionalSuccessors.forEach(
+ exceptionalSuccessor -> {
+ MutableCfBlock exceptionalSuccessorBlock = getBlock(exceptionalSuccessor);
+ block.addExceptionalSuccessor(exceptionalSuccessorBlock);
+ exceptionalSuccessorBlock.addExceptionalPredecessor(block);
+ });
+
+ return instructionIndex;
+ }
+
+ private boolean isBlockEntry(CfInstruction instruction) {
+ return blocks.containsKey(instruction);
+ }
+
+ private boolean isBlockExit(int instructionIndex) {
+ int lastInstructionIndex = code.getInstructions().size() - 1;
+ if (instructionIndex == lastInstructionIndex) {
+ return true;
+ }
+ CfInstruction nextInstruction = code.getInstructions().get(instructionIndex + 1);
+ return isBlockEntry(nextInstruction);
+ }
+
+ private void updateCatchHandlers(
+ CfLabel instruction,
+ Map<CfLabel, List<CfTryCatch>> activeUntilCatchHandlers,
+ Map<CfLabel, List<CfTryCatch>> inactiveUntilCatchHandlers) {
+ // Remove active catch handlers that have expired at the current instruction.
+ activeUntilCatchHandlers.remove(instruction);
+
+ // Promote inactive catch handlers that is activated at the current instruction to active.
+ for (CfTryCatch tryCatch :
+ inactiveUntilCatchHandlers.getOrDefault(instruction, Collections.emptyList())) {
+ assert tryCatch.getEnd() != tryCatch.getStart();
+ activeUntilCatchHandlers
+ .computeIfAbsent(tryCatch.getEnd(), ignoreKey(ArrayList::new))
+ .add(tryCatch);
+ }
+ }
+
+ private boolean verifyCatchHandlersUnchanged(
+ CfLabel instruction,
+ Map<CfLabel, List<CfTryCatch>> activeUntilCatchHandlers,
+ Map<CfLabel, List<CfTryCatch>> inactiveUntilCatchHandlers) {
+ assert !activeUntilCatchHandlers.containsKey(instruction);
+ assert !inactiveUntilCatchHandlers.containsKey(instruction);
+ return true;
+ }
+
+ private void createBlockIfAbsent(CfInstruction blockEntry) {
+ blocks.computeIfAbsent(blockEntry, ignoreKey(MutableCfBlock::new));
+ }
+
+ private MutableCfBlock getBlock(CfInstruction blockEntry) {
+ assert blocks.containsKey(blockEntry);
+ return blocks.get(blockEntry);
+ }
+
+ private MutableCfBlock getBlockOrNull(CfInstruction blockEntry) {
+ return blocks.get(blockEntry);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfIntraproceduralDataflowAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfIntraproceduralDataflowAnalysis.java
new file mode 100644
index 0000000..b4ca696
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfIntraproceduralDataflowAnalysis.java
@@ -0,0 +1,21 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.analysis.framework.intraprocedural.cf;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractState;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractTransferFunction;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.IntraProceduralDataflowAnalysisBase;
+
+public class CfIntraproceduralDataflowAnalysis<StateType extends AbstractState<StateType>>
+ extends IntraProceduralDataflowAnalysisBase<CfBlock, CfInstruction, StateType> {
+
+ public CfIntraproceduralDataflowAnalysis(
+ StateType bottom,
+ CfControlFlowGraph cfg,
+ AbstractTransferFunction<CfBlock, CfInstruction, StateType> transfer) {
+ super(bottom, cfg, transfer);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index b664c13..0d1bf75 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
@@ -48,6 +49,7 @@
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -119,7 +121,7 @@
public enum ThrowingInfo {
NO_THROW,
- CAN_THROW;
+ CAN_THROW
}
public enum EdgeType {
@@ -189,6 +191,73 @@
// Map of registers to current SSA value. Used during SSA numbering and cleared once filled.
private Map<Integer, Value> currentDefinitions = new HashMap<>();
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalPredecessors(
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ TraversalContinuation<BT, CT> traversalContinuation =
+ TraversalContinuation.doContinue(initialValue);
+ for (BasicBlock predecessor : getPredecessors()) {
+ if (predecessor.hasCatchSuccessor(this)) {
+ continue;
+ }
+ traversalContinuation =
+ fn.apply(predecessor, traversalContinuation.asContinue().getValueOrDefault(null));
+ if (traversalContinuation.isBreak()) {
+ break;
+ }
+ }
+ return traversalContinuation;
+ }
+
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalSuccessors(
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ TraversalContinuation<BT, CT> traversalContinuation =
+ TraversalContinuation.doContinue(initialValue);
+ for (int i = successors.size() - numberOfNormalSuccessors(); i < successors.size(); i++) {
+ traversalContinuation =
+ fn.apply(successors.get(i), traversalContinuation.asContinue().getValueOrDefault(null));
+ if (traversalContinuation.isBreak()) {
+ break;
+ }
+ }
+ return traversalContinuation;
+ }
+
+ public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalPredecessors(
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ TraversalContinuation<BT, CT> traversalContinuation =
+ TraversalContinuation.doContinue(initialValue);
+ for (BasicBlock predecessor : getPredecessors()) {
+ if (!predecessor.hasCatchSuccessor(this)) {
+ continue;
+ }
+ traversalContinuation =
+ fn.apply(predecessor, traversalContinuation.asContinue().getValueOrDefault(null));
+ if (traversalContinuation.isBreak()) {
+ break;
+ }
+ }
+ return traversalContinuation;
+ }
+
+ public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ int numberOfExceptionalSuccessors = numberOfExceptionalSuccessors();
+ TraversalContinuation<BT, CT> traversalContinuation =
+ TraversalContinuation.doContinue(initialValue);
+ for (int i = 0; i < numberOfExceptionalSuccessors; i++) {
+ traversalContinuation =
+ fn.apply(successors.get(i), traversalContinuation.asContinue().getValueOrDefault(null));
+ if (traversalContinuation.isBreak()) {
+ break;
+ }
+ }
+ return traversalContinuation;
+ }
+
public void addControlFlowEdgesMayChangeListener(BasicBlockChangeListener listener) {
if (onControlFlowEdgesMayChangeListeners == null) {
// WeakSet to allow the listeners to be garbage collected.
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index b8eb09d..552ebf3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -202,7 +202,7 @@
DexItemFactory dexItemFactory = appView.dexItemFactory();
DexEncodedMethod resolutionResult =
appInfo
- .resolveMethodOnClass(clazz, dexItemFactory.objectMembers.finalize)
+ .resolveMethodOnClassLegacy(clazz, dexItemFactory.objectMembers.finalize)
.getSingleTarget();
return resolutionResult != null && resolutionResult.isProgramMethod(appView);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 53fa359..bf8f7ad 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -16,7 +16,7 @@
import com.android.tools.r8.graph.classmerging.MergedClassesCollection;
import com.android.tools.r8.ir.analysis.TypeChecker;
import com.android.tools.r8.ir.analysis.VerifyTypesHelper;
-import com.android.tools.r8.ir.analysis.framework.intraprocedural.ControlFlowGraph;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.IRControlFlowGraph;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -64,7 +64,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
-public class IRCode implements ControlFlowGraph<BasicBlock, Instruction>, ValueFactory {
+public class IRCode implements IRControlFlowGraph, ValueFactory {
private static final int MAX_MARKING_COLOR = 0x40000000;
@@ -1352,17 +1352,47 @@
return blocks;
}
- @Override
public Collection<BasicBlock> getPredecessors(BasicBlock block) {
return block.getPredecessors();
}
- @Override
public Collection<BasicBlock> getSuccessors(BasicBlock block) {
return block.getSuccessors();
}
@Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalPredecessors(
+ BasicBlock block,
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return block.traverseNormalPredecessors(fn, initialValue);
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseNormalSuccessors(
+ BasicBlock block,
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return block.traverseNormalSuccessors(fn, initialValue);
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalPredecessors(
+ BasicBlock block,
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return block.traverseExceptionalPredecessors(fn, initialValue);
+ }
+
+ @Override
+ public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
+ BasicBlock block,
+ BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ return block.traverseExceptionalSuccessors(fn, initialValue);
+ }
+
+ @Override
public <BT, CT> TraversalContinuation<BT, CT> traverseInstructions(
BasicBlock block,
BiFunction<Instruction, CT, TraversalContinuation<BT, CT>> fn,
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 4e77680..ec23162 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -151,7 +151,7 @@
}
}
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethod(method, getInterfaceBit());
+ appView.appInfo().resolveMethodLegacy(method, getInterfaceBit());
LookupResult lookupResult;
if (refinedReceiverUpperBound != null) {
lookupResult =
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
index c13800c..668d515 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -200,7 +200,7 @@
SingleResolutionResult<?> resolutionResult =
appViewWithClassHierarchy
.appInfo()
- .resolveMethod(getInvokedMethod(), getInterfaceBit())
+ .resolveMethodLegacy(getInvokedMethod(), getInterfaceBit())
.asSingleResolution();
if (resolutionResult == null) {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index f39baa4..b405dbb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -199,7 +199,7 @@
SingleResolutionResult<?> resolutionResult =
appViewWithLiveness
.appInfo()
- .resolveMethod(getInvokedMethod(), isInterface)
+ .resolveMethodLegacy(getInvokedMethod(), isInterface)
.asSingleResolution();
// Verify that the target method is present.
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index baae8e5..85bae5c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -194,7 +194,7 @@
MethodResolutionResult finalizeResolutionResult =
appViewWithClassHierarchy
.appInfo()
- .resolveMethodOnClass(clazz, dexItemFactory.objectMembers.finalize);
+ .resolveMethodOnClassLegacy(clazz, dexItemFactory.objectMembers.finalize);
if (finalizeResolutionResult.isSingleResolution()) {
DexMethod finalizeMethod = finalizeResolutionResult.getSingleTarget().getReference();
if (finalizeMethod != dexItemFactory.enumMembers.finalize
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 fc23097..fa7a539 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
@@ -94,12 +94,12 @@
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.NeverMergeGroup;
+import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import com.google.common.base.Suppliers;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
@@ -1175,7 +1175,7 @@
return timing;
}
- assertionsRewriter.run(method, code, timing);
+ assertionsRewriter.run(method, code, deadCodeRemover, timing);
if (serviceLoaderRewriter != null) {
assert appView.appInfo().hasLiveness();
@@ -1402,7 +1402,7 @@
methodProcessor,
methodProcessingContext,
inliner,
- Suppliers.memoize(
+ new LazyBox<>(
() ->
inliner.createDefaultOracle(
code.context(),
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
index edd4f14..3fc7ad0 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
@@ -78,7 +78,7 @@
if (type == Invoke.Type.INTERFACE || type == Invoke.Type.VIRTUAL) {
// For virtual and interface calls add all potential targets that could be called.
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethod(method, type == Invoke.Type.INTERFACE);
+ appView.appInfo().resolveMethodLegacy(method, type == Invoke.Type.INTERFACE);
DexClassAndMethod target = resolutionResult.getResolutionPair();
if (target != null) {
processInvokeWithDynamicDispatch(type, target, context);
@@ -115,7 +115,7 @@
target,
method -> {
MethodResolutionResult resolution =
- appView.appInfo().resolveMethod(method, isInterface);
+ appView.appInfo().resolveMethodLegacy(method, isInterface);
if (resolution.isVirtualTarget()) {
LookupResult lookupResult =
resolution.lookupVirtualDispatchTargets(context.getHolder(), appView.appInfo());
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 012c31c..ac5addd 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
@@ -373,7 +373,7 @@
assert descriptor.verifyTargetFoundInClass(accessedFrom.getHolderType());
if (implHandle.type.isInvokeStatic()) {
MethodResolutionResult resolution =
- appView.appInfoForDesugaring().resolveMethod(implMethod, implHandle.isInterface);
+ appView.appInfoForDesugaring().resolveMethodLegacy(implMethod, implHandle.isInterface);
if (resolution.isFailedResolution()) {
return new InvalidLambdaImplTarget(
implMethod,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
index bc7a544..d6b10b0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -123,7 +123,7 @@
case INVOKE_INSTANCE: {
DexEncodedMethod target =
appInfo
- .resolveMethodOn(getImplReceiverType(), method, implHandle.isInterface)
+ .resolveMethodOnLegacy(getImplReceiverType(), method, implHandle.isInterface)
.getSingleTarget();
if (target == null) {
target = appInfo.lookupDirectTarget(method, context);
@@ -149,7 +149,9 @@
case INVOKE_INTERFACE: {
DexEncodedMethod target =
- appInfo.resolveMethodOnInterface(getImplReceiverType(), method).getSingleTarget();
+ appInfo
+ .resolveMethodOnInterfaceLegacy(getImplReceiverType(), method)
+ .getSingleTarget();
assert target == null || isInstanceMethod(target);
return target;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index 8935159..e408232 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -120,7 +120,7 @@
MethodResolutionResult resolution =
appView
.appInfoForDesugaring()
- .resolveMethod(bootstrapMethodReference, bootstrapMethodHandle.isInterface);
+ .resolveMethodLegacy(bootstrapMethodReference, bootstrapMethodHandle.isInterface);
if (resolution.isSingleResolution()
&& resolution.asSingleResolution().getResolvedMethod().isStatic()) {
SingleResolutionResult<?> result = resolution.asSingleResolution();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/ApiLevelRange.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/ApiLevelRange.java
new file mode 100644
index 0000000..66a980a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/ApiLevelRange.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary;
+
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Objects;
+
+public class ApiLevelRange {
+
+ private final AndroidApiLevel apiLevelBelowOrEqual;
+ private final AndroidApiLevel apiLevelGreaterOrEqual;
+
+ public ApiLevelRange(int apiLevelBelowOrEqual) {
+ this(AndroidApiLevel.getAndroidApiLevel(apiLevelBelowOrEqual), null);
+ }
+
+ public ApiLevelRange(int apiLevelBelowOrEqual, int apiLevelGreaterOrEqual) {
+ this(
+ AndroidApiLevel.getAndroidApiLevel(apiLevelBelowOrEqual),
+ AndroidApiLevel.getAndroidApiLevel(apiLevelGreaterOrEqual));
+ }
+
+ public ApiLevelRange(
+ AndroidApiLevel apiLevelBelowOrEqual, AndroidApiLevel apiLevelGreaterOrEqual) {
+ this.apiLevelBelowOrEqual = apiLevelBelowOrEqual;
+ this.apiLevelGreaterOrEqual = apiLevelGreaterOrEqual;
+ }
+
+ public int getApiLevelBelowOrEqualAsInt() {
+ return apiLevelBelowOrEqual.getLevel();
+ }
+
+ public int getApiLevelGreaterOrEqualAsInt() {
+ return apiLevelGreaterOrEqual.getLevel();
+ }
+
+ public boolean hasApiLevelGreaterOrEqual() {
+ return apiLevelGreaterOrEqual != null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ApiLevelRange)) {
+ return false;
+ }
+ ApiLevelRange that = (ApiLevelRange) o;
+ return apiLevelBelowOrEqual.equals(that.apiLevelBelowOrEqual)
+ && apiLevelGreaterOrEqual.equals(that.apiLevelGreaterOrEqual);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(apiLevelBelowOrEqual, apiLevelGreaterOrEqual);
+ }
+
+ public int deterministicOrder(ApiLevelRange other) {
+ int compare = apiLevelBelowOrEqual.compareTo(other.apiLevelBelowOrEqual);
+ if (compare != 0) {
+ return compare;
+ }
+ if (apiLevelGreaterOrEqual == null) {
+ if (other.apiLevelGreaterOrEqual == null) {
+ return 0;
+ }
+ return 1;
+ }
+ if (other.apiLevelGreaterOrEqual == null) {
+ return -1;
+ }
+ return apiLevelGreaterOrEqual.compareTo(other.apiLevelGreaterOrEqual);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index f041fe3..55abcef 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -139,7 +139,7 @@
? appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context)
: appView
.appInfoForDesugaring()
- .resolveMethod(invokedMethod, invoke.isInterface())
+ .resolveMethodLegacy(invokedMethod, invoke.isInterface())
.getResolutionPair();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 79f1ff2..47f48d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -287,7 +287,7 @@
+ invokedMethod.holder
+ "#"
+ invokedMethod.name
- + " may not work correctly at runtime (Cannot convert type "
+ + " may not work correctly at runtime (No conversion registered for type "
+ desugaredType
+ ").",
origin,
@@ -520,12 +520,13 @@
.setInterfaces(interfaces)
.setSuperType(superType)
.setInstanceFields(Collections.singletonList(wrapperField))
- .addMethod(methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder));
+ .addMethod(
+ methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder, superType));
return wrapperField;
}
private void buildWrapperConstructor(
- DexEncodedField wrappedValueField, SyntheticMethodBuilder methodBuilder) {
+ DexEncodedField wrappedValueField, SyntheticMethodBuilder methodBuilder, DexType superType) {
methodBuilder
.setName(factory.constructorMethodName)
.setProto(factory.createProto(factory.voidType, wrappedValueField.getType()))
@@ -536,7 +537,8 @@
.disableAndroidApiLevelCheck()
.setCode(
codeSynthesizor ->
- new APIConverterConstructorCfCodeProvider(appView, wrappedValueField.getReference())
+ new APIConverterConstructorCfCodeProvider(
+ appView, wrappedValueField.getReference(), superType)
.generateCfCode());
}
@@ -650,7 +652,7 @@
@Override
public String uniqueIdentifier() {
- return "$wrapper$";
+ return "$wrapper";
}
// Program wrappers are harder to deal with than classpath wrapper because generating a method's
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index 5936d8c..027a2ae 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -47,10 +47,12 @@
static final String PROGRAM_FLAGS_KEY = "program_flags";
static final String API_LEVEL_BELOW_OR_EQUAL_KEY = "api_level_below_or_equal";
+ static final String API_LEVEL_GREATER_OR_EQUAL_KEY = "api_level_greater_or_equal";
static final String WRAPPER_CONVERSION_KEY = "wrapper_conversion";
static final String WRAPPER_CONVERSION_EXCLUDING_KEY = "wrapper_conversion_excluding";
static final String CUSTOM_CONVERSION_KEY = "custom_conversion";
static final String REWRITE_PREFIX_KEY = "rewrite_prefix";
+ static final String DONT_REWRITE_PREFIX_KEY = "dont_rewrite_prefix";
static final String MAINTAIN_PREFIX_KEY = "maintain_prefix";
static final String RETARGET_STATIC_FIELD_KEY = "retarget_static_field";
static final String RETARGET_METHOD_KEY = "retarget_method";
@@ -231,7 +233,13 @@
JsonObject flag = jsonFlagSet.getAsJsonObject();
int api_level_below_or_equal = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
if (minAPILevel <= api_level_below_or_equal) {
- parseFlags(flag, builder);
+ if (flag.has(API_LEVEL_GREATER_OR_EQUAL_KEY)) {
+ if (minAPILevel >= flag.get(API_LEVEL_GREATER_OR_EQUAL_KEY).getAsInt()) {
+ parseFlags(flag, builder);
+ }
+ } else {
+ parseFlags(flag, builder);
+ }
}
}
}
@@ -248,6 +256,12 @@
builder.putMaintainPrefix(maintainPrefix.getAsString());
}
}
+ if (jsonFlagSet.has(DONT_REWRITE_PREFIX_KEY)) {
+ for (JsonElement dontRewritePrefix :
+ jsonFlagSet.get(DONT_REWRITE_PREFIX_KEY).getAsJsonArray()) {
+ builder.putDontRewritePrefix(dontRewritePrefix.getAsString());
+ }
+ }
if (jsonFlagSet.has(REWRITE_DERIVED_PREFIX_KEY)) {
for (Map.Entry<String, JsonElement> prefixToMatch :
jsonFlagSet.get(REWRITE_DERIVED_PREFIX_KEY).getAsJsonObject().entrySet()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index 50e98e1..fc5bcca 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -26,6 +26,7 @@
public class HumanRewritingFlags {
private final Map<String, String> rewritePrefix;
+ private final Set<String> dontRewritePrefix;
private final Set<String> maintainPrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
@@ -42,6 +43,7 @@
HumanRewritingFlags(
Map<String, String> rewritePrefix,
+ Set<String> dontRewritePrefix,
Set<String> maintainPrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
@@ -56,6 +58,7 @@
Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
Map<DexField, FieldAccessFlags> amendLibraryField) {
this.rewritePrefix = rewritePrefix;
+ this.dontRewritePrefix = dontRewritePrefix;
this.maintainPrefix = maintainPrefix;
this.rewriteDerivedPrefix = rewriteDerivedPrefix;
this.emulatedInterfaces = emulateLibraryInterface;
@@ -75,6 +78,7 @@
return new HumanRewritingFlags(
ImmutableMap.of(),
ImmutableSet.of(),
+ ImmutableSet.of(),
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
@@ -98,6 +102,7 @@
reporter,
origin,
rewritePrefix,
+ dontRewritePrefix,
maintainPrefix,
rewriteDerivedPrefix,
emulatedInterfaces,
@@ -117,6 +122,10 @@
return rewritePrefix;
}
+ public Set<String> getDontRewritePrefix() {
+ return dontRewritePrefix;
+ }
+
public Set<String> getMaintainPrefix() {
return maintainPrefix;
}
@@ -185,6 +194,7 @@
private final Origin origin;
private final Map<String, String> rewritePrefix;
+ private final Set<String> dontRewritePrefix;
private final Set<String> maintainPrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
@@ -205,6 +215,7 @@
origin,
new HashMap<>(),
Sets.newIdentityHashSet(),
+ Sets.newIdentityHashSet(),
new HashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
@@ -223,6 +234,7 @@
Reporter reporter,
Origin origin,
Map<String, String> rewritePrefix,
+ Set<String> dontRewritePrefix,
Set<String> maintainPrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
@@ -239,6 +251,7 @@
this.reporter = reporter;
this.origin = origin;
this.rewritePrefix = new HashMap<>(rewritePrefix);
+ this.dontRewritePrefix = Sets.newHashSet(dontRewritePrefix);
this.maintainPrefix = Sets.newHashSet(maintainPrefix);
this.rewriteDerivedPrefix = new HashMap<>(rewriteDerivedPrefix);
this.emulatedInterfaces = new IdentityHashMap<>(emulateLibraryInterface);
@@ -281,6 +294,11 @@
return this;
}
+ public Builder putDontRewritePrefix(String prefix) {
+ dontRewritePrefix.add(prefix);
+ return this;
+ }
+
public Builder putMaintainPrefix(String prefix) {
maintainPrefix.add(prefix);
return this;
@@ -385,6 +403,7 @@
validate();
return new HumanRewritingFlags(
ImmutableMap.copyOf(rewritePrefix),
+ ImmutableSet.copyOf(dontRewritePrefix),
ImmutableSet.copyOf(maintainPrefix),
ImmutableMap.copyOf(rewriteDerivedPrefix),
ImmutableMap.copyOf(emulatedInterfaces),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java
index 69c82a9..ef8be02 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java
@@ -4,24 +4,24 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.ApiLevelRange;
import com.android.tools.r8.origin.Origin;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.Map;
public class MultiAPILevelHumanDesugaredLibrarySpecification {
private final Origin origin;
private final HumanTopLevelFlags topLevelFlags;
- private final Int2ObjectMap<HumanRewritingFlags> commonFlags;
- private final Int2ObjectMap<HumanRewritingFlags> libraryFlags;
- private final Int2ObjectMap<HumanRewritingFlags> programFlags;
+ private final Map<ApiLevelRange, HumanRewritingFlags> commonFlags;
+ private final Map<ApiLevelRange, HumanRewritingFlags> libraryFlags;
+ private final Map<ApiLevelRange, HumanRewritingFlags> programFlags;
public MultiAPILevelHumanDesugaredLibrarySpecification(
Origin origin,
HumanTopLevelFlags topLevelFlags,
- Int2ObjectMap<HumanRewritingFlags> commonFlags,
- Int2ObjectMap<HumanRewritingFlags> libraryFlags,
- Int2ObjectMap<HumanRewritingFlags> programFlags) {
+ Map<ApiLevelRange, HumanRewritingFlags> commonFlags,
+ Map<ApiLevelRange, HumanRewritingFlags> libraryFlags,
+ Map<ApiLevelRange, HumanRewritingFlags> programFlags) {
this.origin = origin;
this.topLevelFlags = topLevelFlags;
this.commonFlags = commonFlags;
@@ -37,28 +37,15 @@
return topLevelFlags;
}
- public Int2ObjectMap<HumanRewritingFlags> getCommonFlags() {
+ public Map<ApiLevelRange, HumanRewritingFlags> getCommonFlags() {
return commonFlags;
}
- public Int2ObjectMap<HumanRewritingFlags> getLibraryFlags() {
+ public Map<ApiLevelRange, HumanRewritingFlags> getLibraryFlags() {
return libraryFlags;
}
- public Int2ObjectMap<HumanRewritingFlags> getProgramFlags() {
+ public Map<ApiLevelRange, HumanRewritingFlags> getProgramFlags() {
return programFlags;
}
-
- public Map<Integer, HumanRewritingFlags> getCommonFlagsForTesting() {
- return commonFlags;
- }
-
- public Map<Integer, HumanRewritingFlags> getLibraryFlagsForTesting() {
- return libraryFlags;
- }
-
- public Map<Integer, HumanRewritingFlags> getProgramFlagsForTesting() {
- return programFlags;
- }
-
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.java
index c059c27..6283419 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.java
@@ -8,10 +8,10 @@
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.ApiLevelRange;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.Reporter;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.IntArraySet;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -23,12 +23,12 @@
MultiAPILevelHumanDesugaredLibrarySpecification specification,
Reporter reporter) {
- IntArraySet apis = new IntArraySet();
+ Set<ApiLevelRange> apis = new HashSet<>();
apis.addAll(specification.getCommonFlags().keySet());
apis.addAll(specification.getLibraryFlags().keySet());
apis.addAll(specification.getProgramFlags().keySet());
- for (Integer api : apis) {
+ for (ApiLevelRange api : apis) {
deduplicateFlags(specification, reporter, api);
}
}
@@ -36,11 +36,11 @@
private static void deduplicateFlags(
MultiAPILevelHumanDesugaredLibrarySpecification specification,
Reporter reporter,
- int api) {
+ ApiLevelRange api) {
- Int2ObjectMap<HumanRewritingFlags> commonFlags = specification.getCommonFlags();
- Int2ObjectMap<HumanRewritingFlags> libraryFlags = specification.getLibraryFlags();
- Int2ObjectMap<HumanRewritingFlags> programFlags = specification.getProgramFlags();
+ Map<ApiLevelRange, HumanRewritingFlags> commonFlags = specification.getCommonFlags();
+ Map<ApiLevelRange, HumanRewritingFlags> libraryFlags = specification.getLibraryFlags();
+ Map<ApiLevelRange, HumanRewritingFlags> programFlags = specification.getProgramFlags();
HumanRewritingFlags library = libraryFlags.get(api);
HumanRewritingFlags program = programFlags.get(api);
@@ -68,7 +68,9 @@
}
private static void putNewFlags(
- int api, Int2ObjectMap<HumanRewritingFlags> flags, HumanRewritingFlags.Builder builder) {
+ ApiLevelRange api,
+ Map<ApiLevelRange, HumanRewritingFlags> flags,
+ HumanRewritingFlags.Builder builder) {
HumanRewritingFlags build = builder.build();
if (build.isEmpty()) {
flags.remove(api);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
index 928eeab..d77a0bc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.AMEND_LIBRARY_METHOD_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.API_LEVEL_BELOW_OR_EQUAL_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.API_LEVEL_GREATER_OR_EQUAL_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.BACKPORT_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.COMMON_FLAGS_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION;
@@ -35,10 +36,9 @@
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.ApiLevelRange;
import com.google.gson.Gson;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -81,14 +81,17 @@
}
private List<Object> rewritingFlagsToString(
- Int2ObjectMap<HumanRewritingFlags> rewritingFlagsMap) {
+ Map<ApiLevelRange, HumanRewritingFlags> rewritingFlagsMap) {
ArrayList<Object> list = new ArrayList<>();
- ArrayList<Integer> apis = new ArrayList<>(rewritingFlagsMap.keySet());
- apis.sort(Comparator.reverseOrder());
- for (int apiBelowOrEqual : apis) {
- HumanRewritingFlags flags = rewritingFlagsMap.get(apiBelowOrEqual);
+ ArrayList<ApiLevelRange> apis = new ArrayList<>(rewritingFlagsMap.keySet());
+ apis.sort((x, y) -> -x.deterministicOrder(y));
+ for (ApiLevelRange range : apis) {
+ HumanRewritingFlags flags = rewritingFlagsMap.get(range);
HashMap<String, Object> toJson = new LinkedHashMap<>();
- toJson.put(API_LEVEL_BELOW_OR_EQUAL_KEY, apiBelowOrEqual);
+ toJson.put(API_LEVEL_BELOW_OR_EQUAL_KEY, range.getApiLevelBelowOrEqualAsInt());
+ if (range.hasApiLevelGreaterOrEqual()) {
+ toJson.put(API_LEVEL_GREATER_OR_EQUAL_KEY, range.getApiLevelGreaterOrEqualAsInt());
+ }
if (!flags.getRewritePrefix().isEmpty()) {
toJson.put(REWRITE_PREFIX_KEY, new TreeMap<>(flags.getRewritePrefix()));
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java
index 9f9fa81..2eab9cf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java
@@ -6,11 +6,12 @@
import com.android.tools.r8.StringResource;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.ApiLevelRange;
import com.android.tools.r8.utils.Reporter;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import java.util.HashMap;
+import java.util.Map;
public class MultiAPILevelHumanDesugaredLibrarySpecificationParser
extends HumanDesugaredLibrarySpecificationParser {
@@ -27,26 +28,31 @@
HumanTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, builder -> {});
- Int2ObjectMap<HumanRewritingFlags> commonFlags = parseAllFlags(COMMON_FLAGS_KEY);
- Int2ObjectMap<HumanRewritingFlags> libraryFlags = parseAllFlags(LIBRARY_FLAGS_KEY);
- Int2ObjectMap<HumanRewritingFlags> programFlags = parseAllFlags(PROGRAM_FLAGS_KEY);
+ Map<ApiLevelRange, HumanRewritingFlags> commonFlags = parseAllFlags(COMMON_FLAGS_KEY);
+ Map<ApiLevelRange, HumanRewritingFlags> libraryFlags = parseAllFlags(LIBRARY_FLAGS_KEY);
+ Map<ApiLevelRange, HumanRewritingFlags> programFlags = parseAllFlags(PROGRAM_FLAGS_KEY);
return new MultiAPILevelHumanDesugaredLibrarySpecification(
getOrigin(), topLevelFlags, commonFlags, libraryFlags, programFlags);
}
- private Int2ObjectMap<HumanRewritingFlags> parseAllFlags(String flagKey) {
+ private Map<ApiLevelRange, HumanRewritingFlags> parseAllFlags(String flagKey) {
JsonElement jsonFlags = required(getJsonConfig(), flagKey);
- Int2ObjectMap<HumanRewritingFlags> flags = new Int2ObjectArrayMap<>();
+ Map<ApiLevelRange, HumanRewritingFlags> flags = new HashMap<>();
for (JsonElement jsonFlagSet : jsonFlags.getAsJsonArray()) {
JsonObject flag = jsonFlagSet.getAsJsonObject();
- int api_level_below_or_equal = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
+ int apiLevelBelowOrEqual = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
+ ApiLevelRange range =
+ flag.has(API_LEVEL_GREATER_OR_EQUAL_KEY)
+ ? new ApiLevelRange(
+ apiLevelBelowOrEqual, flag.get(API_LEVEL_GREATER_OR_EQUAL_KEY).getAsInt())
+ : new ApiLevelRange(apiLevelBelowOrEqual);
HumanRewritingFlags.Builder builder =
- flags.containsKey(api_level_below_or_equal)
- ? flags.get(api_level_below_or_equal).newBuilder(reporter(), getOrigin())
+ flags.containsKey(range)
+ ? flags.get(range).newBuilder(reporter(), getOrigin())
: HumanRewritingFlags.builder(reporter(), getOrigin());
parseFlags(flag, builder);
- flags.put(api_level_below_or_equal, builder.build());
+ flags.put(range, builder.build());
}
return flags;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index a929fb9..8213473 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -175,7 +175,7 @@
DexMethod invokedMethod = cfInvoke.getMethod();
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
MethodResolutionResult resolutionResult =
- appInfo.resolveMethod(invokedMethod, cfInvoke.isInterface());
+ appInfo.resolveMethodLegacy(invokedMethod, cfInvoke.isInterface());
if (!resolutionResult.isSingleResolution()) {
return NO_REWRITING;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
index 6a32412..4ef9c00 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -35,7 +35,7 @@
@Override
public String uniqueIdentifier() {
- return "$retargeter$";
+ return "$retargeter";
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index e1447fb..bfbf6a8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -153,7 +153,7 @@
DexMethod forwardMethod = syntheticHelper.forwardingMethod(descriptor);
assert forwardMethod != null && forwardMethod != target;
DexEncodedMethod resolvedMethod =
- appView.appInfoForDesugaring().resolveMethod(target, true).getResolvedMethod();
+ appView.appInfoForDesugaring().resolveMethodLegacy(target, true).getResolvedMethod();
assert resolvedMethod != null;
DexEncodedMethod desugaringForwardingMethod =
DexEncodedMethod.createDesugaringForwardingMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 78fc59f..8cb5743 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -27,6 +27,7 @@
private final boolean libraryCompilation;
private final Map<DexString, DexString> descriptorPrefix;
private final Set<DexString> descriptorMaintainPrefix;
+ private final Set<DexString> descriptorDontRewritePrefix;
private final Map<DexString, Map<DexString, DexString>> descriptorDifferentPrefix;
private final Set<DexString> usedPrefix = Sets.newIdentityHashSet();
@@ -40,7 +41,8 @@
this.synthesizedPrefix = humanSpec.getSynthesizedLibraryClassesPackagePrefix();
this.libraryCompilation = humanSpec.isLibraryCompilation();
this.descriptorPrefix = convertRewritePrefix(rewritingFlags.getRewritePrefix());
- this.descriptorMaintainPrefix = convertMaintainPrefix(rewritingFlags.getMaintainPrefix());
+ this.descriptorDontRewritePrefix = convertPrefixSet(rewritingFlags.getDontRewritePrefix());
+ this.descriptorMaintainPrefix = convertPrefixSet(rewritingFlags.getMaintainPrefix());
this.descriptorDifferentPrefix =
convertRewriteDifferentPrefix(rewritingFlags.getRewriteDerivedPrefix());
}
@@ -102,6 +104,11 @@
}
private void registerClassType(DexType type) {
+ // TODO(b/222647019): To remove, the problem is that the prefix java.nio.channels.FileChannel
+ // matches java.nio.channels.FileChannel$MapMode.
+ if (type.toString().equals("java.nio.channels.FileChannel$MapMode")) {
+ return;
+ }
registerType(type);
registerMaintainType(type);
registerDifferentType(type);
@@ -110,6 +117,9 @@
private void registerType(DexType type) {
DexType rewrittenType = rewrittenType(type);
if (rewrittenType != null) {
+ if (prefixMatching(type, descriptorDontRewritePrefix) != null) {
+ return;
+ }
builder.rewriteType(type, rewrittenType);
}
}
@@ -174,7 +184,7 @@
return mapBuilder.build();
}
- private ImmutableSet<DexString> convertMaintainPrefix(Set<String> maintainPrefix) {
+ private ImmutableSet<DexString> convertPrefixSet(Set<String> maintainPrefix) {
ImmutableSet.Builder<DexString> builder = ImmutableSet.builder();
for (String prefix : maintainPrefix) {
builder.add(toDescriptorPrefix(prefix));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
index 9487210..18147b5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
@@ -12,9 +12,12 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
+import com.android.tools.r8.utils.MethodSignatureEquivalence;
+import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -22,6 +25,7 @@
public class HumanToMachineWrapperConverter {
+ private final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
private final AppInfoWithClassHierarchy appInfo;
private final Set<DexType> missingClasses = Sets.newIdentityHashSet();
@@ -56,6 +60,10 @@
private List<DexMethod> allImplementedMethods(
DexClass wrapperClass, Set<DexMethod> excludedMethods) {
+ HashSet<Wrapper<DexMethod>> wrappers = new HashSet<>();
+ for (DexMethod excludedMethod : excludedMethods) {
+ wrappers.add(equivalence.wrap(excludedMethod));
+ }
LinkedList<DexClass> workList = new LinkedList<>();
List<DexMethod> implementedMethods = new ArrayList<>();
workList.add(wrapperClass);
@@ -64,7 +72,7 @@
for (DexEncodedMethod virtualMethod : dexClass.virtualMethods()) {
if (!virtualMethod.isPrivateMethod()) {
assert virtualMethod.isProtectedMethod() || virtualMethod.isPublicMethod();
- boolean alreadyAdded = excludedMethods.contains(virtualMethod.getReference());
+ boolean alreadyAdded = wrappers.contains(equivalence.wrap(virtualMethod.getReference()));
// This looks quadratic but given the size of the collections met in practice for
// desugared libraries (Max ~15) it does not matter.
if (!alreadyAdded) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
index bd26b562..baa4178 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.ApiLevelRange;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
@@ -32,22 +33,27 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
public class LegacyToHumanSpecificationConverter {
private static final String WRAPPER_PREFIX = "__wrapper__.";
private static final AndroidApiLevel LEGACY_HACK_LEVEL = AndroidApiLevel.N_MR1;
private final Timing timing;
+ private final Set<String> missingClasses = new HashSet<>();
+ private final Set<String> missingMethods = new HashSet<>();
public LegacyToHumanSpecificationConverter(Timing timing) {
this.timing = timing;
@@ -81,14 +87,15 @@
AppForSpecConversion.readAppForTesting(desugaredJDKLib, androidLib, options, true, timing);
HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
- Int2ObjectArrayMap<HumanRewritingFlags> commonFlags =
+ Map<ApiLevelRange, HumanRewritingFlags> commonFlags =
convertRewritingFlagMap(legacySpec.getCommonFlags(), app, origin);
- Int2ObjectArrayMap<HumanRewritingFlags> programFlags =
+ Map<ApiLevelRange, HumanRewritingFlags> programFlags =
convertRewritingFlagMap(legacySpec.getProgramFlags(), app, origin);
- Int2ObjectArrayMap<HumanRewritingFlags> libraryFlags =
+ Map<ApiLevelRange, HumanRewritingFlags> libraryFlags =
convertRewritingFlagMap(legacySpec.getLibraryFlags(), app, origin);
legacyLibraryFlagHacks(libraryFlags, app, origin);
+ reportWarnings(app.options.reporter);
MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
new MultiAPILevelHumanDesugaredLibrarySpecification(
@@ -135,16 +142,34 @@
humanRewritingFlags = builder.build();
timing.end();
}
-
+ reportWarnings(app.options.reporter);
timing.end();
return new HumanDesugaredLibrarySpecification(
humanTopLevelFlags, humanRewritingFlags, legacySpec.isLibraryCompilation());
}
+ private void reportWarnings(Reporter reporter) {
+ String errorSdk = "This usually means that the compilation SDK is absent or too old.";
+ if (!missingClasses.isEmpty()) {
+ reporter.warning(
+ "Cannot retarget core lib member for missing classes: "
+ + missingClasses
+ + ". "
+ + errorSdk);
+ }
+ if (!missingMethods.isEmpty()) {
+ reporter.warning(
+ "Should have found a method (library specifications) for "
+ + missingMethods
+ + ". "
+ + errorSdk);
+ }
+ }
+
private void legacyLibraryFlagHacks(
- Int2ObjectArrayMap<HumanRewritingFlags> libraryFlags, DexApplication app, Origin origin) {
- int level = LEGACY_HACK_LEVEL.getLevel();
- HumanRewritingFlags humanRewritingFlags = libraryFlags.get(level);
+ Map<ApiLevelRange, HumanRewritingFlags> libraryFlags, DexApplication app, Origin origin) {
+ ApiLevelRange range = new ApiLevelRange(LEGACY_HACK_LEVEL.getLevel());
+ HumanRewritingFlags humanRewritingFlags = libraryFlags.get(range);
if (humanRewritingFlags == null) {
// Skip CHM only configuration.
return;
@@ -152,7 +177,7 @@
HumanRewritingFlags.Builder builder =
humanRewritingFlags.newBuilder(app.options.reporter, origin);
legacyLibraryFlagHacks(app.dexItemFactory(), builder);
- libraryFlags.put(level, builder.build());
+ libraryFlags.put(range, builder.build());
}
private void legacyLibraryFlagHacks(
@@ -186,10 +211,11 @@
builder.retargetMethod(source, target);
}
- private Int2ObjectArrayMap<HumanRewritingFlags> convertRewritingFlagMap(
+ private Map<ApiLevelRange, HumanRewritingFlags> convertRewritingFlagMap(
Int2ObjectMap<LegacyRewritingFlags> libFlags, DexApplication app, Origin origin) {
- Int2ObjectArrayMap<HumanRewritingFlags> map = new Int2ObjectArrayMap<>();
- libFlags.forEach((key, flags) -> map.put((int) key, convertRewritingFlags(flags, app, origin)));
+ Map<ApiLevelRange, HumanRewritingFlags> map = new HashMap<>();
+ libFlags.forEach(
+ (key, flags) -> map.put(new ApiLevelRange(key), convertRewritingFlags(flags, app, origin)));
return map;
}
@@ -257,7 +283,11 @@
typeMap.forEach(
(type, rewrittenType) -> {
DexClass dexClass = app.definitionFor(type);
- assert dexClass != null;
+ if (dexClass == null) {
+ assert false : "Cannot retarget core lib member for missing class " + type;
+ missingClasses.add(type.toSourceString());
+ return;
+ }
List<DexClassAndMethod> methodsWithName =
findMethodsWithName(name, dexClass, builder, app);
for (DexClassAndMethod dexClassAndMethod : methodsWithName) {
@@ -297,12 +327,11 @@
DexEncodedMethod.builder().setMethod(method).setAccessFlags(flags).build();
return ImmutableList.of(DexClassAndMethod.create(clazz, build));
}
- assert !found.isEmpty()
- : "Should have found a method (library specifications) for "
- + clazz.toSourceString()
- + "."
- + methodName
- + ". Maybe the library used for the compilation should be newer.";
+ if (found.isEmpty()) {
+ String warning = clazz.toSourceString() + "." + methodName;
+ assert false : "Should have found a method (library specifications) for " + warning;
+ missingMethods.add(warning);
+ }
return found;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
index 5c89290..9630887 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
@@ -70,7 +70,7 @@
CfInvoke invoke = instruction.asInvoke();
DexMethod invokedMethod = invoke.getMethod();
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethod(invokedMethod, invoke.isInterface());
+ appView.appInfo().resolveMethodLegacy(invokedMethod, invoke.isInterface());
if (shouldRewriteInvokeToThrow(invoke, resolutionResult)) {
return computeInvokeAsThrowRewrite(appView, invoke, resolutionResult);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 266b1c5..0806685 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -646,7 +646,7 @@
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
for (Wrapper<DexMethod> signature : emulatedInterfaceInfo.signatures.signatures) {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(clazz, signature.get());
+ appInfo.resolveMethodOnClassLegacy(clazz, signature.get());
if (resolutionResult.isFailedResolution()) {
return true;
}
@@ -685,7 +685,7 @@
private void resolveForwardForSignature(
DexClass clazz, DexMethod method, BiConsumer<DexClassAndMethod, DexMethod> addForward) {
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOn(clazz, method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnLegacy(clazz, method);
if (resolutionResult.isFailedResolution()
|| resolutionResult.asSuccessfulMemberResolutionResult().getResolvedMember().isStatic()) {
// When doing resolution we may find a static or private targets and bubble up the failed
@@ -702,7 +702,7 @@
resolutionResult.asSuccessfulMemberResolutionResult().getResolvedMember().isStatic());
}
if (staticTarget.isAssigned() && staticTarget.isTrue()) {
- resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+ resolutionResult = appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
}
if (resolutionResult.isFailedResolution()) {
if (resolutionResult.isIncompatibleClassChangeErrorResult()) {
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 3919202..eda530c 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
@@ -263,7 +263,10 @@
}
assert verifyKind(method, kinds -> kinds.COMPANION_CLASS);
DexClassAndMethod resolvedMethod =
- appView.appInfoForDesugaring().resolveMethod(method.getMethod(), true).getResolutionPair();
+ appView
+ .appInfoForDesugaring()
+ .resolveMethodLegacy(method.getMethod(), true)
+ .getResolutionPair();
return ensureDefaultAsMethodOfCompanionClassStub(resolvedMethod).getReference();
}
@@ -274,7 +277,7 @@
DexClassAndMethod method =
appView
.appInfoForDesugaring()
- .resolveMethod(emulatedDispatchMethod.getMethod(), true)
+ .resolveMethodLegacy(emulatedDispatchMethod.getMethod(), true)
.getResolutionPair();
assert verifyKind(emulatedDispatchMethod, kinds -> kinds.EMULATED_INTERFACE_CLASS);
if (method.isProgramMethod()) {
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 7b3bb07..bc8ebd0 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
@@ -307,7 +307,7 @@
// would change behavior from throwing ICCE to dispatching to the companion class method.
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
MethodResolutionResult resolution =
- appInfo.resolveMethod(invoke.getMethod(), invoke.isInterface());
+ appInfo.resolveMethodLegacy(invoke.getMethod(), invoke.isInterface());
if (!resolution.isSingleResolution()
|| !resolution.asSingleResolution().getResolvedMethod().isStatic()) {
return DesugarDescription.nothing();
@@ -408,7 +408,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfoForDesugaring()
- .resolveMethodOnInterface(holder, invoke.getMethod())
+ .resolveMethodOnInterfaceLegacy(holder, invoke.getMethod())
.asSingleResolution();
if (holder.isInterface() && shouldRewriteToInvokeToThrow(resolutionResult, true)) {
return computeInvokeAsThrowRewrite(invoke, resolutionResult, context);
@@ -437,7 +437,7 @@
AppInfoWithClassHierarchy appInfoForDesugaring = appView.appInfoForDesugaring();
SingleResolutionResult<?> resolution =
appInfoForDesugaring
- .resolveMethod(invoke.getMethod(), invoke.isInterface())
+ .resolveMethodLegacy(invoke.getMethod(), invoke.isInterface())
.asSingleResolution();
if (resolution != null
&& resolution.getResolvedMethod().isPrivate()
@@ -454,7 +454,9 @@
private DesugarDescription computeEmulatedInterfaceVirtualDispatchOrNull(CfInvoke invoke) {
MethodResolutionResult resolutionResult =
- appView.appInfoForDesugaring().resolveMethod(invoke.getMethod(), invoke.isInterface());
+ appView
+ .appInfoForDesugaring()
+ .resolveMethodLegacy(invoke.getMethod(), invoke.isInterface());
DerivedMethod emulatedDispatchMethod =
helper.computeEmulatedInterfaceDispatchMethod(resolutionResult);
if (emulatedDispatchMethod == null) {
@@ -492,7 +494,7 @@
}
MethodResolutionResult resolution =
- appView.appInfoForDesugaring().resolveMethod(invokedMethod, invoke.isInterface());
+ appView.appInfoForDesugaring().resolveMethodLegacy(invokedMethod, invoke.isInterface());
if (resolution.isFailedResolution()) {
return computeInvokeAsThrowRewrite(invoke, null, context);
}
@@ -638,7 +640,10 @@
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfoForDesugaring().resolveMethodOn(clazz, invokedMethod).asSingleResolution();
+ appView
+ .appInfoForDesugaring()
+ .resolveMethodOnLegacy(clazz, invokedMethod)
+ .asSingleResolution();
if (clazz.isInterface() && shouldRewriteToInvokeToThrow(resolutionResult, false)) {
return computeInvokeAsThrowRewrite(invoke, resolutionResult, context);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
index b8b50d9..6a57dae 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
@@ -114,7 +114,7 @@
@Override
public String uniqueIdentifier() {
- return "$emulatedInterface$";
+ return "$emulatedInterface";
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
index 6a84f09..366ee34 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
@@ -476,7 +476,7 @@
@Override
public String uniqueIdentifier() {
- return "$record$";
+ return "$record";
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
index 72b8d6a..1961b30 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
@@ -32,12 +32,14 @@
import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.ThrowingCharIterator;
import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.WorkList;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
import java.io.UTFDataFormatException;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
public class AssertionsRewriter {
@@ -274,6 +276,7 @@
* }
* }
* </pre>
+ *
* For Kotlin the Class instance method desiredAssertionStatus() is only called for the class
* kotlin._Assertions, where kotlin._Assertions.class.desiredAssertionStatus() is read into the
* static field kotlin._Assertions.ENABLED.
@@ -311,7 +314,8 @@
* }
* </pre>
*
- * With the rewriting below and AssertionTransformation.DISABLE (and other rewritings) the resulting code is:
+ * With the rewriting below and AssertionTransformation.DISABLE (and other rewritings) the
+ * resulting code is:
*
* <pre>
* class A {
@@ -332,23 +336,26 @@
* }
* }
* </pre>
-
+ *
* NOTE: that in Kotlin the assertion condition is always calculated. So it is still present in
* the code and even for AssertionTransformation.DISABLE.
*/
- public void run(DexEncodedMethod method, IRCode code, Timing timing) {
+ public void run(
+ DexEncodedMethod method, IRCode code, DeadCodeRemover deadCodeRemover, Timing timing) {
if (enabled) {
timing.begin("Rewrite assertions");
- runInternal(method, code);
+ if (runInternal(method, code)) {
+ deadCodeRemover.run(code, timing);
+ }
assert code.isConsistentSSA(appView);
timing.end();
}
}
- private void runInternal(DexEncodedMethod method, IRCode code) {
+ private boolean runInternal(DexEncodedMethod method, IRCode code) {
ConfigurationEntryWithDexString configuration = getTransformationForMethod(method);
if (configuration.isPassthrough()) {
- return;
+ return false;
}
DexEncodedMethod clinit;
// If the <clinit> of this class did not have have code to turn on assertions don't try to
@@ -358,20 +365,25 @@
} else {
DexClass clazz = appView.definitionFor(method.getHolderType());
if (clazz == null) {
- return;
+ return false;
}
clinit = clazz.getClassInitializer();
}
// For the transformation to rewrite the throw with a callback collect information on the
// blocks covered by the if (!$assertionsDisabled or ENABLED) condition together with weather
// the assertion handling is on the true or false branch.
- Map<If, Boolean> assertionEntryIfs = new IdentityHashMap<>();
+ Map<If, Boolean> assertionEntryIfs = new Reference2BooleanOpenHashMap<>();
Map<Throw, BasicBlock> throwSuccessorAfterHandler = new IdentityHashMap<>();
+ Set<BasicBlock> assertionBlocks = Sets.newIdentityHashSet();
+ Map<If, Boolean> additionalAssertionsEnabledIfs = new Reference2BooleanOpenHashMap<>();
if (configuration.isAssertionHandler()) {
LazyBox<DominatorTree> dominatorTree = new LazyBox<>(() -> new DominatorTree(code));
code.getBlocks()
.forEach(
basicBlock -> {
+ if (assertionBlocks.contains(basicBlock)) {
+ return;
+ }
If theIf = isCheckAssertionsEnabledBlock(basicBlock);
if (theIf != null) {
// All blocks dominated by the if is the assertion code. For Java it is on the
@@ -382,25 +394,42 @@
theIf.lhs().getDefinition().asStaticGet());
BasicBlock assertionBlockEntry =
theIf.targetFromBoolean(conditionForAssertionBlock);
- List<BasicBlock> blocks =
+ List<BasicBlock> dominatedBlocks =
dominatorTree.computeIfAbsent().dominatedBlocks(assertionBlockEntry);
- Throw throwInstruction = isAlwaysThrowingEntry(assertionBlockEntry, blocks);
+ Throw throwInstruction =
+ dominatedBlocksHasSingleThrow(assertionBlockEntry, dominatedBlocks);
if (throwInstruction != null) {
assertionEntryIfs.put(theIf, conditionForAssertionBlock);
throwSuccessorAfterHandler.put(
throwInstruction, theIf.targetFromBoolean(!conditionForAssertionBlock));
+ // Collect any additional assertions enabled checks dominated by the current
+ // assertions entry check.
+ dominatedBlocks.forEach(
+ block -> {
+ If additionalAssertionsEnabledIf = isCheckAssertionsEnabledBlock(block);
+ if (additionalAssertionsEnabledIf != null) {
+ additionalAssertionsEnabledIfs.put(
+ additionalAssertionsEnabledIf,
+ !isUsingJavaAssertionsDisabledField(
+ additionalAssertionsEnabledIf
+ .lhs()
+ .getDefinition()
+ .asStaticGet()));
+ }
+ });
+ assertionBlocks.addAll(dominatedBlocks);
}
}
});
}
assert assertionEntryIfs.size() == throwSuccessorAfterHandler.size();
-
// For javac generated code it is assumed that the code in <clinit> will tell if the code
// in other methods of the class can have assertion checks.
boolean isInitializerEnablingJavaVmAssertions =
clinit != null && clinit.getOptimizationInfo().isInitializerEnablingJavaVmAssertions();
// This code will process the assertion code in all methods including <clinit>.
InstructionListIterator iterator = code.instructionListIterator();
+ boolean needsDeadCodeRemoval = false;
while (iterator.hasNext()) {
Instruction current = iterator.next();
if (current.isInvokeMethod()) {
@@ -446,11 +475,12 @@
if (current.isIf()) {
If ifInstruction = current.asIf();
if (assertionEntryIfs.containsKey(ifInstruction)) {
- ifInstruction
- .targetFromBoolean(!assertionEntryIfs.get(ifInstruction))
- .unlinkSinglePredecessorSiblingsAllowed();
- ifInstruction.lhs().removeUser(ifInstruction);
- iterator.replaceCurrentInstruction(new Goto());
+ forceAssertionsEnabled(ifInstruction, assertionEntryIfs, iterator);
+ needsDeadCodeRemoval = true;
+ }
+ if (additionalAssertionsEnabledIfs.containsKey(ifInstruction)) {
+ forceAssertionsEnabled(ifInstruction, additionalAssertionsEnabledIfs, iterator);
+ needsDeadCodeRemoval = true;
}
} else if (current.isThrow()) {
Throw throwInstruction = current.asThrow();
@@ -469,6 +499,7 @@
}
}
}
+ return needsDeadCodeRemoval;
}
private void rewriteKotlinAssertionEnable(
@@ -541,15 +572,9 @@
: null;
}
- private Throw isAlwaysThrowingEntry(BasicBlock block, List<BasicBlock> blocks) {
- WorkList<BasicBlock> workList = WorkList.newIdentityWorkList(block);
+ private Throw dominatedBlocksHasSingleThrow(BasicBlock block, List<BasicBlock> dominatedBlocks) {
Throw theThrow = null;
- while (workList.hasNext()) {
- BasicBlock current = workList.next();
- workList.addIfNotSeen(current.getNormalSuccessors());
- if (!blocks.containsAll(current.getNormalSuccessors())) {
- return null;
- }
+ for (BasicBlock current : dominatedBlocks) {
if (current.exit().isReturn()) {
return null;
}
@@ -562,4 +587,13 @@
}
return theThrow;
}
+
+ private void forceAssertionsEnabled(
+ If ifInstruction, Map<If, Boolean> targetMap, InstructionListIterator iterator) {
+ ifInstruction
+ .targetFromBoolean(!targetMap.get(ifInstruction))
+ .unlinkSinglePredecessorSiblingsAllowed();
+ ifInstruction.lhs().removeUser(ifInstruction);
+ iterator.replaceCurrentInstruction(new Goto());
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java b/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
index 1c49fc9..df9d508 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
@@ -230,7 +230,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .unsafeResolveMethodDueToDexFormat(invoke.getInvokedMethod())
+ .unsafeResolveMethodDueToDexFormatLegacy(invoke.getInvokedMethod())
.asSingleResolution();
if (resolutionResult == null) {
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 86578a2..3d9d2b8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -98,11 +98,11 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOutputMode;
+import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.LongInterval;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.base.Suppliers;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -145,7 +145,6 @@
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.function.Supplier;
public class CodeRewriter {
@@ -1838,8 +1837,7 @@
// and ConstStrings with one user.
// TODO(ager): Generalize this to shorten live ranges for more instructions? Currently
// doing so seems to make things worse.
- Supplier<DominatorTree> dominatorTreeMemoization =
- Suppliers.memoize(() -> new DominatorTree(code));
+ LazyBox<DominatorTree> dominatorTreeMemoization = new LazyBox<>(() -> new DominatorTree(code));
Map<BasicBlock, Map<Value, Instruction>> addConstantInBlock = new IdentityHashMap<>();
LinkedList<BasicBlock> blocks = code.blocks;
for (BasicBlock block : blocks) {
@@ -1945,7 +1943,7 @@
private void shortenLiveRangesInsideBlock(
IRCode code,
BasicBlock block,
- Supplier<DominatorTree> dominatorTreeMemoization,
+ LazyBox<DominatorTree> dominatorTreeMemoization,
Map<BasicBlock, Map<Value, Instruction>> addConstantInBlock,
Predicate<ConstInstruction> selector) {
InstructionListIterator iterator = block.listIterator(code);
@@ -2014,7 +2012,7 @@
userBlocks.add(phi.getBlock());
}
// Locate the closest dominator block for all user blocks.
- DominatorTree dominatorTree = dominatorTreeMemoization.get();
+ DominatorTree dominatorTree = dominatorTreeMemoization.computeIfAbsent();
BasicBlock dominator = dominatorTree.closestDominator(userBlocks);
// If the closest dominator block is a block that uses the constant for a phi the constant
// needs to go in the immediate dominator block so that it is available for phi moves.
@@ -2816,9 +2814,9 @@
return;
}
- Supplier<Long2ReferenceMap<List<ConstNumber>>> constantsByValue =
- Suppliers.memoize(() -> getConstantsByValue(code));
- Supplier<DominatorTree> dominatorTree = Suppliers.memoize(() -> new DominatorTree(code));
+ LazyBox<Long2ReferenceMap<List<ConstNumber>>> constantsByValue =
+ new LazyBox<>(() -> getConstantsByValue(code));
+ LazyBox<DominatorTree> dominatorTree = new LazyBox<>(() -> new DominatorTree(code));
boolean changed = false;
for (BasicBlock block : code.blocks) {
@@ -2908,7 +2906,7 @@
}
}
- if (constantsByValue.get().isEmpty()) {
+ if (constantsByValue.computeIfAbsent().isEmpty()) {
break;
}
}
@@ -2954,16 +2952,17 @@
long withValue,
Value newValue,
BasicBlock dominator,
- Supplier<Long2ReferenceMap<List<ConstNumber>>> constantsByValueSupplier,
+ LazyBox<Long2ReferenceMap<List<ConstNumber>>> constantsByValueSupplier,
IRCode code,
- Supplier<DominatorTree> dominatorTree) {
+ LazyBox<DominatorTree> dominatorTree) {
if (newValue.hasLocalInfo()) {
// We cannot replace a constant with a value that has local info, because that could change
// debugging behavior.
return false;
}
- Long2ReferenceMap<List<ConstNumber>> constantsByValue = constantsByValueSupplier.get();
+ Long2ReferenceMap<List<ConstNumber>> constantsByValue =
+ constantsByValueSupplier.computeIfAbsent();
List<ConstNumber> constantsWithValue = constantsByValue.get(withValue);
if (constantsWithValue == null || constantsWithValue.isEmpty()) {
return false;
@@ -3003,7 +3002,7 @@
continue;
}
- if (dominatorTree.get().dominatedBy(block, dominator)) {
+ if (dominatorTree.computeIfAbsent().dominatedBy(block, dominator)) {
if (newValue.getType().lessThanOrEqual(value.getType(), appView)) {
value.replaceUsers(newValue);
block.listIterator(code, constNumber).removeOrReplaceByDebugLocalRead();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index 9ba2beb..5930cd3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -369,7 +369,10 @@
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().resolveMethodOnClass(target.getHolderType(), target).asSingleResolution();
+ appView
+ .appInfo()
+ .resolveMethodOnClassLegacy(target.getHolderType(), target)
+ .asSingleResolution();
if (resolutionResult == null
|| resolutionResult
.isAccessibleForVirtualDispatchFrom(context, appView.appInfo())
@@ -385,7 +388,7 @@
}
SingleResolutionResult<?> newResolutionResult =
- appView.appInfo().resolveMethodOnClass(receiverType, target).asSingleResolution();
+ appView.appInfo().resolveMethodOnClassLegacy(receiverType, target).asSingleResolution();
if (newResolutionResult == null
|| newResolutionResult
.isAccessibleForVirtualDispatchFrom(context, appView.appInfo())
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
index 265d097..257af5e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
@@ -139,7 +139,7 @@
SingleResolutionResult<?> resolutionResult =
appInfoWithLiveness
- .resolveMethod(invoke.getInvokedMethod(), invoke.getInterfaceBit())
+ .resolveMethodLegacy(invoke.getInvokedMethod(), invoke.getInterfaceBit())
.asSingleResolution();
if (resolutionResult == null
|| resolutionResult
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 4ca07c5..4be71a5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -963,7 +963,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethod(invokedMethod, invoke.getInterfaceBit())
+ .resolveMethodLegacy(invokedMethod, invoke.getInterfaceBit())
.asSingleResolution();
if (resolutionResult == null
|| resolutionResult.isAccessibleFrom(context, appView).isPossiblyFalse()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index 4cf1c8c..59e06c4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -175,7 +175,7 @@
return ConstraintWithTarget.ALWAYS;
}
MethodResolutionResult resolutionResult =
- appView.appInfo().unsafeResolveMethodDueToDexFormat(lookup);
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(lookup);
DexEncodedMethod target =
singleTargetWhileVerticalClassMerging(
resolutionResult, context, MethodResolutionResult::lookupInvokeDirectTarget);
@@ -207,7 +207,7 @@
return ConstraintWithTarget.ALWAYS;
}
MethodResolutionResult resolutionResult =
- appView.appInfo().unsafeResolveMethodDueToDexFormat(lookup);
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(lookup);
DexEncodedMethod target =
singleTargetWhileVerticalClassMerging(
resolutionResult, context, MethodResolutionResult::lookupInvokeStaticTarget);
@@ -364,7 +364,8 @@
// Perform resolution and derive inlining constraints based on the accessibility of the
// resolution result.
- MethodResolutionResult resolutionResult = appView.appInfo().resolveMethod(method, isInterface);
+ MethodResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodLegacy(method, isInterface);
if (!resolutionResult.isVirtualTarget()) {
return ConstraintWithTarget.NEVER;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 09b614e..d572d2f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -290,7 +290,10 @@
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().unsafeResolveMethodDueToDexFormat(invokedMethod).asSingleResolution();
+ appView
+ .appInfo()
+ .unsafeResolveMethodDueToDexFormatLegacy(invokedMethod)
+ .asSingleResolution();
if (resolutionResult == null) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
index 1a35898..e111ec0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
@@ -91,7 +91,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethod(invoke.getInvokedMethod(), invoke.getInterfaceBit())
+ .resolveMethodLegacy(invoke.getInvokedMethod(), invoke.getInterfaceBit())
.asSingleResolution();
if (resolutionResult == null
|| resolutionResult.isAccessibleFrom(method, appView).isPossiblyFalse()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java
index c82a122..e55a1b0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java
@@ -30,7 +30,7 @@
public class NaturalIntLoopRemover {
public void run(AppView<?> appView, IRCode code) {
- if (!appView.testing().enableExperimentalLoopUnrolling) {
+ if (!appView.options().enableLoopUnrolling) {
return;
}
boolean loopRemoved = false;
@@ -87,6 +87,9 @@
if (!analyzeLoopExit(loopBody, comparison, builder)) {
return false;
}
+ if (!analyzePhiUses(loopBody, comparison, builder)) {
+ return false;
+ }
NaturalIntLoopWithKnowIterations loop = builder.build();
@@ -98,6 +101,42 @@
}
/**
+ * The loop unroller removes phis corresponding to the loop backjump. There are three scenarios:
+ * (1) The loop has a single exit point analyzed, phis used outside the loop are replaced by the
+ * value at the end of the loop body.
+ * (2) The phis are unused outside the loop, and they are simply removed.
+ * (3) The loop has multiple exits and the phis are used outside the loop, this would require
+ * dealing with complex merge point and postponing phis after the loop, we bail out.
+ */
+ private boolean analyzePhiUses(
+ Set<BasicBlock> loopBody, If comparison, NaturalIntLoopWithKnowIterations.Builder builder) {
+ // Check for single exit scenario.
+ Set<BasicBlock> successors = Sets.newIdentityHashSet();
+ for (BasicBlock basicBlock : loopBody) {
+ successors.addAll(basicBlock.getSuccessors());
+ }
+ successors.removeAll(loopBody);
+ if (successors.size() == 1) {
+ assert successors.iterator().next() == builder.getLoopExit();
+ return true;
+ }
+ // Check phis are unused outside the loop.
+ for (Phi phi : comparison.getBlock().getPhis()) {
+ for (Instruction use : phi.uniqueUsers()) {
+ if (!loopBody.contains(use.getBlock())) {
+ return false;
+ }
+ }
+ for (Phi phiUse : phi.uniquePhiUsers()) {
+ if (!loopBody.contains(phiUse.getBlock())) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
* Verifies the loop is well formed: the comparison on the int iterator should jump to a loop exit
* on one side and to the loop body on the other side.
*/
@@ -305,6 +344,10 @@
this.loopBodyEntry = loopBodyEntry;
}
+ public BasicBlock getLoopExit() {
+ return loopExit;
+ }
+
public void setLoopBody(Set<BasicBlock> loopBody) {
this.loopBody = loopBody;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index 5966a8c..a3c270a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -512,7 +512,7 @@
appView
.appInfo()
.withClassHierarchy()
- .unsafeResolveMethodDueToDexFormat(invoke.getInvokedMethod())
+ .unsafeResolveMethodDueToDexFormatLegacy(invoke.getInvokedMethod())
.getResolvedProgramMethod();
if (resolvedMethod != null) {
markClassAsInitialized(resolvedMethod.getHolderType());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java
index 20b26b0..afed4c2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java
@@ -23,13 +23,12 @@
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.InternalOptions;
-import com.google.common.base.Suppliers;
+import com.android.tools.r8.utils.LazyBox;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import java.util.Collections;
import java.util.ListIterator;
-import java.util.function.Supplier;
public class RuntimeWorkaroundCodeRewriter {
@@ -87,8 +86,8 @@
return;
}
DexItemFactory factory = options.itemFactory;
- final Supplier<DexMethod> javaLangLangSignum =
- Suppliers.memoize(
+ LazyBox<DexMethod> javaLangLangSignum =
+ new LazyBox<>(
() ->
factory.createMethod(
factory.createString("Ljava/lang/Long;"),
@@ -118,7 +117,7 @@
Value longValue = firstMaterializing.inValues().get(0);
InvokeStatic invokeLongSignum =
new InvokeStatic(
- javaLangLangSignum.get(), null, Collections.singletonList(longValue));
+ javaLangLangSignum.computeIfAbsent(), null, Collections.singletonList(longValue));
ensureThrowingInstructionBefore(code, firstMaterializing, it, invokeLongSignum);
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
index 75e94fb..9027ee1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
@@ -219,16 +219,20 @@
result = ResultState.NOT_SATISFIED;
}
- public void addSatisfyingInstruction(Instruction instruction) {
+ public SimpleEffectAnalysisResultBuilder addSatisfyingInstruction(Instruction instruction) {
satisfyingInstructions.add(instruction);
+ return this;
}
- public void setFailingBlocksForPartialResults(List<BasicBlock> basicBlocks) {
+ public SimpleEffectAnalysisResultBuilder setFailingBlocksForPartialResults(
+ List<BasicBlock> basicBlocks) {
this.failingBlocksForPartialResults = basicBlocks;
+ return this;
}
- public void setResult(ResultState result) {
+ public SimpleEffectAnalysisResultBuilder setResult(ResultState result) {
this.result = result;
+ return this;
}
public SimpleEffectAnalysisResult build() {
@@ -246,63 +250,69 @@
public static SimpleEffectAnalysisResult run(IRCode code, InstructionAnalysis analysis) {
SimpleEffectAnalysisResultBuilder builder = SimpleEffectAnalysisResult.builder();
IntBox visitedInstructions = new IntBox();
- new StatefulDepthFirstSearchWorkList<BasicBlock, ResultStateWithPartialBlocks>() {
+ TraversalContinuation<Void, ResultStateWithPartialBlocks> runResult =
+ new StatefulDepthFirstSearchWorkList<BasicBlock, ResultStateWithPartialBlocks, Void>() {
- @Override
- protected TraversalContinuation<?, ?> process(
- DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks> node,
- Function<BasicBlock, DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks>>
- childNodeConsumer) {
- InstructionEffect effect = NO_EFFECT;
- for (Instruction instruction : node.getNode().getInstructions()) {
- if (visitedInstructions.getAndIncrement() > analysis.maxNumberOfInstructions()) {
- builder.fail();
- return doBreak();
- }
- effect = analysis.analyze(instruction);
- if (!effect.isNoEffect()) {
- if (effect.isDesired()) {
- builder.addSatisfyingInstruction(instruction);
+ @Override
+ protected TraversalContinuation<Void, ResultStateWithPartialBlocks> process(
+ DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks> node,
+ Function<BasicBlock, DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks>>
+ childNodeConsumer) {
+ InstructionEffect effect = NO_EFFECT;
+ for (Instruction instruction : node.getNode().getInstructions()) {
+ if (visitedInstructions.getAndIncrement() > analysis.maxNumberOfInstructions()) {
+ return doBreak();
+ }
+ effect = analysis.analyze(instruction);
+ if (!effect.isNoEffect()) {
+ if (effect.isDesired()) {
+ builder.addSatisfyingInstruction(instruction);
+ }
+ break;
+ }
}
- break;
- }
- }
- if (effect.isNoEffect()) {
- List<BasicBlock> successors = analysis.getSuccessors(node.getNode());
- for (BasicBlock successor : successors) {
- DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks> childNode =
- childNodeConsumer.apply(successor);
- if (childNode.hasState()) {
- // If we see a block where the children have not been processed we cannot guarantee
- // all paths having the effect since - ex. we could have a non-terminating loop.
- builder.fail();
- return doBreak();
+ if (effect.isNoEffect()) {
+ List<BasicBlock> successors = analysis.getSuccessors(node.getNode());
+ for (BasicBlock successor : successors) {
+ DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks> childNode =
+ childNodeConsumer.apply(successor);
+ if (childNode.hasState()) {
+ // If we see a block where the children have not been processed we cannot
+ // guarantee all paths having the effect since - ex. we could have a
+ // non-terminating loop.
+ return doBreak();
+ }
+ }
}
+ node.setState(
+ new ResultStateWithPartialBlocks(effect.toResultState(), ImmutableList.of()));
+ return doContinue();
}
- }
- node.setState(new ResultStateWithPartialBlocks(effect.toResultState(), ImmutableList.of()));
- return doContinue();
- }
- @Override
- protected TraversalContinuation<?, ?> joiner(
- DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks> node,
- List<DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks>> childNodes) {
- ResultStateWithPartialBlocks resultState = node.getState();
- if (resultState.state.isNotComputed()) {
- resultState = resultState.joinChildren(childNodes);
- } else {
- assert resultState.state.isSatisfied() || resultState.state.isNotSatisfied();
- assert childNodes.isEmpty();
- }
- node.setState(resultState);
- if (node.getNode().isEntry()) {
- builder.setResult(resultState.state);
- builder.setFailingBlocksForPartialResults(resultState.failingBlocks);
- }
- return doContinue();
- }
- }.run(code.entryBlock());
+ @Override
+ protected TraversalContinuation<Void, ResultStateWithPartialBlocks> joiner(
+ DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks> node,
+ List<DFSNodeWithState<BasicBlock, ResultStateWithPartialBlocks>> childNodes) {
+ ResultStateWithPartialBlocks resultState = node.getState();
+ if (resultState.state.isNotComputed()) {
+ resultState = resultState.joinChildren(childNodes);
+ } else {
+ assert resultState.state.isSatisfied() || resultState.state.isNotSatisfied();
+ assert childNodes.isEmpty();
+ }
+ node.setState(resultState);
+ return doContinue(resultState);
+ }
+ }.run(code.entryBlock());
+
+ if (runResult.isBreak()) {
+ builder.fail();
+ } else {
+ ResultStateWithPartialBlocks resultState = runResult.asContinue().getValue();
+ builder
+ .setResult(resultState.state)
+ .setFailingBlocksForPartialResults(resultState.failingBlocks);
+ }
return builder.build();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index ccbd132..7607596 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -29,13 +29,13 @@
import com.android.tools.r8.ir.optimize.inliner.InliningIRProvider;
import com.android.tools.r8.ir.optimize.string.StringOptimizer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.LazyBox;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Supplier;
public final class ClassInliner {
@@ -135,7 +135,7 @@
MethodProcessor methodProcessor,
MethodProcessingContext methodProcessingContext,
Inliner inliner,
- Supplier<InliningOracle> defaultOracle) {
+ LazyBox<InliningOracle> defaultOracle) {
// Collect all the new-instance and static-get instructions in the code before inlining.
List<Instruction> roots =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 0b876a7..10cdd99 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -65,6 +65,7 @@
import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotInliningReporter;
import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
@@ -79,7 +80,6 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
-import java.util.function.Supplier;
final class InlineCandidateProcessor {
@@ -218,7 +218,7 @@
*
* @return null if all users are eligible, or the first ineligible user.
*/
- InstructionOrPhi areInstanceUsersEligible(Supplier<InliningOracle> defaultOracle) {
+ InstructionOrPhi areInstanceUsersEligible(LazyBox<InliningOracle> defaultOracle) {
// No Phi users.
if (eligibleInstance.hasPhiUsers()) {
return eligibleInstance.firstPhiUser(); // Not eligible.
@@ -294,7 +294,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethod(invoke.getInvokedMethod(), invoke.getInterfaceBit())
+ .resolveMethodLegacy(invoke.getInvokedMethod(), invoke.getInterfaceBit())
.asSingleResolution();
if (resolutionResult == null
|| resolutionResult.isAccessibleFrom(method, appView).isPossiblyFalse()) {
@@ -1028,7 +1028,7 @@
// signature of the invocation resolves to a private or static method.
// TODO(b/147212189): Why not inline private methods? If access is permitted it is valid.
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(eligibleClass, callee);
+ appView.appInfo().resolveMethodOnClassLegacy(eligibleClass, callee);
if (resolutionResult.isSingleResolution()
&& !resolutionResult.getSingleTarget().isNonPrivateVirtualMethod()) {
return false;
@@ -1073,7 +1073,7 @@
InvokeMethod invoke,
SingleResolutionResult<?> resolutionResult,
ProgramMethod singleTarget,
- Supplier<InliningOracle> defaultOracle,
+ LazyBox<InliningOracle> defaultOracle,
Set<Instruction> indirectUsers) {
if (!((invoke.isInvokeDirect() && !invoke.isInvokeConstructor(dexItemFactory))
|| invoke.isInvokeInterface()
@@ -1092,7 +1092,7 @@
}
// Check if the method is inline-able by standard inliner.
- InliningOracle oracle = defaultOracle.get();
+ InliningOracle oracle = defaultOracle.computeIfAbsent();
if (!oracle.passesInliningConstraints(
invoke,
resolutionResult,
@@ -1176,7 +1176,10 @@
NonEmptyParameterUsage nonEmptyUsage = usage.asNonEmpty();
for (DexMethod invokedMethod : nonEmptyUsage.getMethodCallsWithParameterAsReceiver()) {
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().resolveMethodOn(eligibleClass, invokedMethod).asSingleResolution();
+ appView
+ .appInfo()
+ .resolveMethodOnLegacy(eligibleClass, invokedMethod)
+ .asSingleResolution();
if (resolutionResult == null || !resolutionResult.getResolvedHolder().isProgramClass()) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
index ebad797..e4bbb6c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
@@ -250,7 +250,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOnClassHolder(invoke.getInvokedMethod())
+ .resolveMethodOnClassHolderLegacy(invoke.getInvokedMethod())
.asSingleResolution();
if (resolutionResult == null) {
return state.abandonClassInliningInCurrentContexts(receiverRoot);
@@ -289,7 +289,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOnInterfaceHolder(invoke.getInvokedMethod())
+ .resolveMethodOnInterfaceHolderLegacy(invoke.getInvokedMethod())
.asSingleResolution();
if (resolutionResult == null) {
return state.abandonClassInliningInCurrentContexts(receiverRoot);
@@ -305,7 +305,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .unsafeResolveMethodDueToDexFormat(invoke.getInvokedMethod())
+ .unsafeResolveMethodDueToDexFormatLegacy(invoke.getInvokedMethod())
.asSingleResolution();
if (resolutionResult != null
&& resolutionResult.getResolvedMethod().getReference()
@@ -331,7 +331,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOnClassHolder(invoke.getInvokedMethod())
+ .resolveMethodOnClassHolderLegacy(invoke.getInvokedMethod())
.asSingleResolution();
if (resolutionResult == null) {
return state.abandonClassInliningInCurrentContexts(receiverRoot);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index cfec469..ed028ee 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -461,7 +461,7 @@
ProgramMethod checkNotZeroMethod =
appView
.appInfo()
- .resolveMethodOnClassHolder(checkNotZeroMethodReference)
+ .resolveMethodOnClassHolderLegacy(checkNotZeroMethodReference)
.getResolvedProgramMethod();
if (checkNotZeroMethod != null) {
EnumUnboxerMethodClassification classification =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
index 0d6fa85..f2fbb4c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -160,7 +160,8 @@
DexEncodedMethod singleTarget =
appView
.appInfo()
- .resolveMethodOnClass(enumFieldType.getClassType(), factory.objectMembers.toString)
+ .resolveMethodOnClassLegacy(
+ enumFieldType.getClassType(), factory.objectMembers.toString)
.getSingleTarget();
if (singleTarget != null && singleTarget.getReference() != factory.enumMembers.toString) {
continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 8d2e339..c02b953 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -965,7 +965,7 @@
MethodResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(clazz, appView.dexItemFactory().objectMembers.finalize);
+ .resolveMethodOnClassLegacy(clazz, appView.dexItemFactory().objectMembers.finalize);
DexEncodedMethod target = resolutionResult.getSingleTarget();
return target != null
&& target.getReference() != dexItemFactory.enumMembers.finalize
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/sideeffects/JavaLangObjectsSideEffectCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/sideeffects/JavaLangObjectsSideEffectCollection.java
index 9d4ae82..bd7edf7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/sideeffects/JavaLangObjectsSideEffectCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/sideeffects/JavaLangObjectsSideEffectCollection.java
@@ -49,7 +49,7 @@
DexClass clazz = appInfo.definitionFor(classType);
if (clazz != null && clazz.isEffectivelyFinal(appView)) {
SingleResolutionResult<?> resolutionResult =
- appInfo.resolveMethodOn(clazz, toStringMethodReference).asSingleResolution();
+ appInfo.resolveMethodOnLegacy(clazz, toStringMethodReference).asSingleResolution();
if (resolutionResult != null
&& !resolutionResult.getResolvedMethod().getOptimizationInfo().mayHaveSideEffects()) {
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
index ef2f42d..d2ec4d6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -174,7 +174,10 @@
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().resolveMethodOn(superClass, method.getReference()).asSingleResolution();
+ appView
+ .appInfo()
+ .resolveMethodOnLegacy(superClass, method.getReference())
+ .asSingleResolution();
if (resolutionResult == null) {
return null;
}
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 9402a62..afadf9f 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
@@ -576,11 +576,14 @@
public static class APIConverterConstructorCfCodeProvider extends SyntheticCfCodeProvider {
- DexField wrapperField;
+ private final DexField wrapperField;
+ private final DexType superType;
- public APIConverterConstructorCfCodeProvider(AppView<?> appView, DexField wrapperField) {
+ public APIConverterConstructorCfCodeProvider(
+ AppView<?> appView, DexField wrapperField, DexType superType) {
super(appView, wrapperField.holder);
this.wrapperField = wrapperField;
+ this.superType = superType;
}
@Override
@@ -592,9 +595,7 @@
new CfInvoke(
Opcodes.INVOKESPECIAL,
factory.createMethod(
- factory.objectType,
- factory.createProto(factory.voidType),
- factory.constructorMethodName),
+ superType, factory.createProto(factory.voidType), factory.constructorMethodName),
false));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.type), 1));
diff --git a/src/main/java/com/android/tools/r8/lightir/ByteArrayIterator.java b/src/main/java/com/android/tools/r8/lightir/ByteArrayIterator.java
new file mode 100644
index 0000000..c1f72dc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/ByteArrayIterator.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+import it.unimi.dsi.fastutil.bytes.ByteIterator;
+
+/** Simple implementation of an iterator over a primitive byte array. */
+public class ByteArrayIterator implements ByteIterator {
+
+ private final int size;
+ private final byte[] buffer;
+ private int index = 0;
+
+ public ByteArrayIterator(byte[] bytes) {
+ size = bytes.length;
+ buffer = bytes;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return index < size;
+ }
+
+ @Override
+ public byte nextByte() {
+ return buffer[index++];
+ }
+
+ @Override
+ public Byte next() {
+ return nextByte();
+ }
+
+ @Override
+ public int skip(int i) {
+ int actual = index + i <= size ? i : size - index;
+ index += actual;
+ return actual;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/ByteArrayWriter.java b/src/main/java/com/android/tools/r8/lightir/ByteArrayWriter.java
new file mode 100644
index 0000000..7636ed4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/ByteArrayWriter.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+import java.io.ByteArrayOutputStream;
+
+/** Simple implementation to construct a primitive byte array. */
+public class ByteArrayWriter implements ByteWriter {
+
+ // Backing is just the default capacity reallocating java byte array.
+ private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ @Override
+ public void put(int u1) {
+ assert ByteUtils.isU1(u1);
+ buffer.write(u1);
+ }
+
+ public byte[] toByteArray() {
+ return buffer.toByteArray();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/ByteUtils.java b/src/main/java/com/android/tools/r8/lightir/ByteUtils.java
new file mode 100644
index 0000000..40a80d2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/ByteUtils.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+/** Simple utilities for byte encodings. */
+public class ByteUtils {
+
+ public static boolean isU1(int value) {
+ return 0 <= value && value <= 0xFF;
+ }
+
+ // Lossy truncation of an integer value to its lowest byte.
+ private static int truncateToU1(int value) {
+ return value & 0xFF;
+ }
+
+ public static int ensureU1(int value) {
+ assert isU1(value);
+ return truncateToU1(value);
+ }
+
+ public static int fromU1(byte value) {
+ return value & 0xFF;
+ }
+
+ public static int intEncodingSize(int value) {
+ return 4;
+ }
+
+ public static void writeEncodedInt(int value, ByteWriter writer) {
+ assert 4 == intEncodingSize(value);
+ writer.put(truncateToU1(value >> 24));
+ writer.put(truncateToU1(value >> 16));
+ writer.put(truncateToU1(value >> 8));
+ writer.put(truncateToU1(value));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/ByteWriter.java b/src/main/java/com/android/tools/r8/lightir/ByteWriter.java
new file mode 100644
index 0000000..0a2a75e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/ByteWriter.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+/** Most primitive interface for providing consumer to the LIRWriter. */
+public interface ByteWriter {
+
+ /** Put a byte value, must represent an unsigned byte (int between 0 and 255). */
+ void put(int u1);
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRBasicInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LIRBasicInstructionCallback.java
new file mode 100644
index 0000000..a08c036
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LIRBasicInstructionCallback.java
@@ -0,0 +1,18 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+public interface LIRBasicInstructionCallback {
+
+ /**
+ * Most basic callback for interpreting LIR.
+ *
+ * @param opcode The opcode of the instruction (See {@code LIROpcodes} for values).
+ * @param operandsOffsetInBytes The offset into the byte stream at which the instruction's payload
+ * starts.
+ * @param operandsSizeInBytes The total size of the instruction's payload (excluding the opcode
+ * itself an any payload size encoding).
+ */
+ void onInstruction(int opcode, int operandsOffsetInBytes, int operandsSizeInBytes);
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java b/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
new file mode 100644
index 0000000..7ced9ef
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+import com.android.tools.r8.graph.DexItem;
+import it.unimi.dsi.fastutil.objects.Reference2IntMap;
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+
+public class LIRBuilder {
+
+ private final ByteArrayWriter byteWriter = new ByteArrayWriter();
+ private final LIRWriter writer = new LIRWriter(byteWriter);
+ private final Reference2IntMap<DexItem> constants;
+
+ public LIRBuilder() {
+ constants = new Reference2IntOpenHashMap<>();
+ }
+
+ private int getConstantIndex(DexItem item) {
+ int nextIndex = constants.size();
+ Integer oldIndex = constants.putIfAbsent(item, nextIndex);
+ return oldIndex != null ? oldIndex : nextIndex;
+ }
+
+ public LIRBuilder addNop() {
+ writer.writeOneByteInstruction(LIROpcodes.NOP);
+ return this;
+ }
+
+ public LIRBuilder addConstNull() {
+ writer.writeOneByteInstruction(LIROpcodes.ACONST_NULL);
+ return this;
+ }
+
+ public LIRBuilder addConstInt(int value) {
+ if (0 <= value && value <= 5) {
+ writer.writeOneByteInstruction(LIROpcodes.ICONST_0 + value);
+ } else {
+ writer.writeInstruction(LIROpcodes.ICONST, ByteUtils.intEncodingSize(value));
+ ByteUtils.writeEncodedInt(value, writer::writeOperand);
+ }
+ return this;
+ }
+
+ public LIRCode build() {
+ int constantsCount = constants.size();
+ DexItem[] constantTable = new DexItem[constantsCount];
+ constants.forEach((item, index) -> constantTable[index] = item);
+ return new LIRCode(constantTable, byteWriter.toByteArray());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRCode.java b/src/main/java/com/android/tools/r8/lightir/LIRCode.java
new file mode 100644
index 0000000..c91dbd9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LIRCode.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+import com.android.tools.r8.graph.DexItem;
+
+public class LIRCode implements Iterable<LIRInstructionView> {
+
+ private final DexItem[] constants;
+ private final byte[] instructions;
+
+ public static LIRBuilder builder() {
+ return new LIRBuilder();
+ }
+
+ // Should be constructed using LIRBuilder.
+ LIRCode(DexItem[] constants, byte[] instructions) {
+ this.constants = constants;
+ this.instructions = instructions;
+ }
+
+ @Override
+ public LIRIterator iterator() {
+ return new LIRIterator(new ByteArrayIterator(instructions));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRInstructionView.java b/src/main/java/com/android/tools/r8/lightir/LIRInstructionView.java
new file mode 100644
index 0000000..59051e3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LIRInstructionView.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+/**
+ * Abstract view of a LIR instruction.
+ *
+ * <p>The view should not be considered a representation of an instruction as the underlying data
+ * can change. The view callbacks allow interpreting the instruction at different levels of
+ * abstraction depending on need.
+ */
+public interface LIRInstructionView {
+
+ void accept(LIRBasicInstructionCallback eventCallback);
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRIterator.java b/src/main/java/com/android/tools/r8/lightir/LIRIterator.java
new file mode 100644
index 0000000..e05d521
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LIRIterator.java
@@ -0,0 +1,61 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+import it.unimi.dsi.fastutil.bytes.ByteIterator;
+import java.util.Iterator;
+
+/**
+ * Basic iterator over the light IR.
+ *
+ * <p>This iterator is internally a zero-allocation parser with the "elements" as a view onto the
+ * current state.
+ */
+public class LIRIterator implements Iterator<LIRInstructionView>, LIRInstructionView {
+
+ private final ByteIterator iterator;
+
+ private int currentByteIndex = 0;
+ private int currentOpcode = -1;
+ private int currentOperandSize = 0;
+
+ public LIRIterator(ByteIterator iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public LIRInstructionView next() {
+ currentOpcode = u1();
+ if (LIROpcodes.isOneByteInstruction(currentOpcode)) {
+ currentOperandSize = 0;
+ } else {
+ // Any instruction that is not a single byte has a two-byte header. The second byte is the
+ // size of the variable width operand payload.
+ currentOperandSize = u1();
+ skip(currentOperandSize);
+ }
+ return this;
+ }
+
+ @Override
+ public void accept(LIRBasicInstructionCallback eventCallback) {
+ int operandsOffset = currentByteIndex - currentOperandSize;
+ eventCallback.onInstruction(currentOpcode, operandsOffset, currentOperandSize);
+ }
+
+ private void skip(int i) {
+ currentByteIndex += i;
+ iterator.skip(i);
+ }
+
+ private int u1() {
+ ++currentByteIndex;
+ return ByteUtils.fromU1(iterator.nextByte());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java b/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
new file mode 100644
index 0000000..85cc9f1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
@@ -0,0 +1,182 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+/**
+ * Constants related to LIR.
+ *
+ * <p>The constants generally follow the bytecode values as defined by the classfile format.
+ */
+public interface LIROpcodes {
+
+ static boolean isOneByteInstruction(int opcode) {
+ assert opcode >= NOP;
+ return opcode <= DCONST_1;
+ }
+
+ // Instructions maintaining the same opcode as defined in CF.
+ int NOP = 0;
+ int ACONST_NULL = 1;
+ int ICONST_M1 = 2;
+ int ICONST_0 = 3;
+ int ICONST_1 = 4;
+ int ICONST_2 = 5;
+ int ICONST_3 = 6;
+ int ICONST_4 = 7;
+ int ICONST_5 = 8;
+ int LCONST_0 = 9;
+ int LCONST_1 = 10;
+ int FCONST_0 = 11;
+ int FCONST_1 = 12;
+ int FCONST_2 = 13;
+ int DCONST_0 = 14;
+ int DCONST_1 = 15;
+ // int BIPUSH = 16;
+ // int SIPUSH = 17;
+ int LDC = 18;
+ // int ILOAD = 21;
+ // int LLOAD = 22;
+ // int FLOAD = 23;
+ // int DLOAD = 24;
+ // int ALOAD = 25;
+ int IALOAD = 46;
+ int LALOAD = 47;
+ int FALOAD = 48;
+ int DALOAD = 49;
+ int AALOAD = 50;
+ int BALOAD = 51;
+ int CALOAD = 52;
+ int SALOAD = 53;
+ // int ISTORE = 54;
+ // int LSTORE = 55;
+ // int FSTORE = 56;
+ // int DSTORE = 57;
+ // int ASTORE = 58;
+ int IASTORE = 79;
+ int LASTORE = 80;
+ int FASTORE = 81;
+ int DASTORE = 82;
+ int AASTORE = 83;
+ int BASTORE = 84;
+ int CASTORE = 85;
+ int SASTORE = 86;
+ // int POP = 87;
+ // int POP2 = 88;
+ // int DUP = 89;
+ // int DUP_X1 = 90;
+ // int DUP_X2 = 91;
+ // int DUP2 = 92;
+ // int DUP2_X1 = 93;
+ // int DUP2_X2 = 94;
+ // int SWAP = 95;
+ int IADD = 96;
+ int LADD = 97;
+ int FADD = 98;
+ int DADD = 99;
+ int ISUB = 100;
+ int LSUB = 101;
+ int FSUB = 102;
+ int DSUB = 103;
+ int IMUL = 104;
+ int LMUL = 105;
+ int FMUL = 106;
+ int DMUL = 107;
+ int IDIV = 108;
+ int LDIV = 109;
+ int FDIV = 110;
+ int DDIV = 111;
+ int IREM = 112;
+ int LREM = 113;
+ int FREM = 114;
+ int DREM = 115;
+ int INEG = 116;
+ int LNEG = 117;
+ int FNEG = 118;
+ int DNEG = 119;
+ int ISHL = 120;
+ int LSHL = 121;
+ int ISHR = 122;
+ int LSHR = 123;
+ int IUSHR = 124;
+ int LUSHR = 125;
+ int IAND = 126;
+ int LAND = 127;
+ int IOR = 128;
+ int LOR = 129;
+ int IXOR = 130;
+ int LXOR = 131;
+ // int IINC = 132;
+ int I2L = 133;
+ int I2F = 134;
+ int I2D = 135;
+ int L2I = 136;
+ int L2F = 137;
+ int L2D = 138;
+ int F2I = 139;
+ int F2L = 140;
+ int F2D = 141;
+ int D2I = 142;
+ int D2L = 143;
+ int D2F = 144;
+ int I2B = 145;
+ int I2C = 146;
+ int I2S = 147;
+ int LCMP = 148;
+ int FCMPL = 149;
+ int FCMPG = 150;
+ int DCMPL = 151;
+ int DCMPG = 152;
+ int IFEQ = 153;
+ int IFNE = 154;
+ int IFLT = 155;
+ int IFGE = 156;
+ int IFGT = 157;
+ int IFLE = 158;
+ int IF_ICMPEQ = 159;
+ int IF_ICMPNE = 160;
+ int IF_ICMPLT = 161;
+ int IF_ICMPGE = 162;
+ int IF_ICMPGT = 163;
+ int IF_ICMPLE = 164;
+ int IF_ACMPEQ = 165;
+ int IF_ACMPNE = 166;
+ int GOTO = 167;
+ // int JSR = 168;
+ // int RET = 169;
+ int TABLESWITCH = 170;
+ int LOOKUPSWITCH = 171;
+ int IRETURN = 172;
+ int LRETURN = 173;
+ int FRETURN = 174;
+ int DRETURN = 175;
+ int ARETURN = 176;
+ int RETURN = 177;
+ int GETSTATIC = 178;
+ int PUTSTATIC = 179;
+ int GETFIELD = 180;
+ int PUTFIELD = 181;
+ int INVOKEVIRTUAL = 182;
+ int INVOKESPECIAL = 183;
+ int INVOKESTATIC = 184;
+ int INVOKEINTERFACE = 185;
+ int INVOKEDYNAMIC = 186;
+ int NEW = 187;
+ int NEWARRAY = 188;
+ int ANEWARRAY = 189;
+ int ARRAYLENGTH = 190;
+ int ATHROW = 191;
+ int CHECKCAST = 192;
+ int INSTANCEOF = 193;
+ int MONITORENTER = 194;
+ int MONITOREXIT = 195;
+ int MULTIANEWARRAY = 197;
+ int IFNULL = 198;
+ int IFNONNULL = 199;
+
+ // Non-CF instructions.
+ int ICONST = 200;
+ int LCONST = 201;
+ int FCONST = 202;
+ int DCONST = 203;
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRWriter.java b/src/main/java/com/android/tools/r8/lightir/LIRWriter.java
new file mode 100644
index 0000000..074726d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LIRWriter.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+/**
+ * Lowest level writer for constructing LIR encoded data.
+ *
+ * <p>This writer deals with just the instruction and operand encodings. For higher level structure,
+ * such as the constant pool, see LIRBuilder.
+ */
+public class LIRWriter {
+
+ private final ByteWriter writer;
+ private int pendingOperandBytes = 0;
+
+ public LIRWriter(ByteWriter writer) {
+ this.writer = writer;
+ }
+
+ public void writeOneByteInstruction(int opcode) {
+ assert LIROpcodes.isOneByteInstruction(opcode);
+ assert pendingOperandBytes == 0;
+ writer.put(ByteUtils.ensureU1(opcode));
+ }
+
+ public void writeInstruction(int opcode, int operandsSizeInBytes) {
+ assert pendingOperandBytes == 0;
+ writer.put(ByteUtils.ensureU1(opcode));
+ writer.put(ByteUtils.ensureU1(operandsSizeInBytes));
+ pendingOperandBytes = operandsSizeInBytes;
+ }
+
+ public void writeOperand(int u1) {
+ assert pendingOperandBytes > 0;
+ pendingOperandBytes--;
+ writer.put(ByteUtils.ensureU1(u1));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index 7657adc..0b0d20f 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -47,16 +47,6 @@
private final Map<String, ClassNamingForNameMapper.Builder> mapping = new HashMap<>();
private LinkedHashSet<MapVersionMappingInformation> mapVersions = new LinkedHashSet<>();
- private final Set<String> buildForClass;
-
- private Builder(Set<String> buildForClass) {
- this.buildForClass = buildForClass;
- }
-
- @Override
- public boolean buildForClass(String typeName) {
- return buildForClass == null || buildForClass.contains(typeName);
- }
@Override
public ClassNamingForNameMapper.Builder classNamingBuilder(
@@ -88,11 +78,7 @@
}
public static Builder builder() {
- return new Builder(null);
- }
-
- public static Builder builder(Set<String> buildForClass) {
- return new Builder(buildForClass);
+ return new Builder();
}
public static ClassNameMapper mapperFromFile(Path path) throws IOException {
@@ -182,7 +168,7 @@
diagnosticsHandler != null ? diagnosticsHandler : new Reporter(),
allowEmptyMappedRanges,
allowExperimentalMapping)) {
- ClassNameMapper.Builder builder = ClassNameMapper.builder(buildForClass);
+ ClassNameMapper.Builder builder = ClassNameMapper.builder();
proguardReader.parse(builder);
return builder.build();
}
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index ca7fa4e..242b6e1 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -382,7 +382,8 @@
return;
}
- MethodResolutionResult resolutionResult = appView.appInfo().resolveMethodOn(holder, method);
+ MethodResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodOnLegacy(holder, method);
if (resolutionResult.isSingleResolution()) {
DexEncodedMethod resolvedMethod = resolutionResult.getSingleTarget();
if (resolvedMethod.getReference() == method) {
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
index bf18111..ddd882c 100644
--- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -106,7 +106,8 @@
return true;
}
- MethodResolutionResult resolution = appView.appInfo().unsafeResolveMethodDueToDexFormat(method);
+ MethodResolutionResult resolution =
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method);
assert resolution != null;
if (resolution.isSingleResolution()) {
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMap.java b/src/main/java/com/android/tools/r8/naming/ProguardMap.java
index d1e7463..6b95444 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMap.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMap.java
@@ -16,10 +16,6 @@
abstract Builder setCurrentMapVersion(MapVersionMappingInformation mapVersion);
abstract ProguardMap build();
-
- public boolean buildForClass(String typeName) {
- return true;
- }
}
boolean hasMapping(DexType type);
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 bbea4c4..f28d4bc 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -261,18 +261,11 @@
String after = parseType(false);
skipWhitespace();
expect(':');
- if (mapBuilder.buildForClass(after)) {
- ClassNaming.Builder currentClassBuilder =
- mapBuilder.classNamingBuilder(after, before, getPosition());
- skipWhitespace();
- if (nextLine()) {
- parseMemberMappings(currentClassBuilder);
- }
- } else {
- do {
- lineOffset = line.length();
- nextLine();
- } while (hasLine() && !isClassMapping());
+ ClassNaming.Builder currentClassBuilder =
+ mapBuilder.classNamingBuilder(after, before, getPosition());
+ skipWhitespace();
+ if (nextLine()) {
+ parseMemberMappings(currentClassBuilder);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index 2e373e0..a03ff91 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -116,7 +116,7 @@
currentResolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(currentResolvedHolder.getSuperType(), original)
+ .resolveMethodOnClassLegacy(currentResolvedHolder.getSuperType(), original)
.asSingleResolution();
} else {
break;
@@ -244,15 +244,15 @@
}
private MethodResolutionResult resolveMethodOnClass(DexMethod method) {
- return appView.appInfo().resolveMethodOnClass(method.holder, method);
+ return appView.appInfo().resolveMethodOnClassLegacy(method.holder, method);
}
private MethodResolutionResult resolveMethodOnInterface(DexMethod method) {
- return appView.appInfo().resolveMethodOnInterface(method.holder, method);
+ return appView.appInfo().resolveMethodOnInterfaceLegacy(method.holder, method);
}
private MethodResolutionResult resolveMethod(DexMethod method) {
- return appView.appInfo().unsafeResolveMethodDueToDexFormat(method);
+ return appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method);
}
private void computeMethodRebinding(MethodAccessInfoCollection methodAccessInfoCollection) {
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
index b819518..6782981 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
@@ -216,7 +216,7 @@
DexClass holder = appView.contextIndependentDefinitionFor(reference.getHolderType());
if (holder != null) {
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().resolveMethodOn(holder, reference).asSingleResolution();
+ appView.appInfo().resolveMethodOnLegacy(holder, reference).asSingleResolution();
if (resolutionResult != null && resolutionResult.getResolvedHolder() != holder) {
recordNonReboundMethodAccess(
reference, resolutionResult.getResolvedMethod().getReference());
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java
index 38c08c6..6ae7365 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java
@@ -216,7 +216,7 @@
return;
}
SingleResolutionResult<?> resolutionResult =
- appInfo.resolveMethodOn(holder, method).asSingleResolution();
+ appInfo.resolveMethodOnLegacy(holder, method).asSingleResolution();
if (resolutionResult == null) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingUtils.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingUtils.java
index cbb7761..1b72c3a 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingUtils.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingUtils.java
@@ -22,7 +22,7 @@
return false;
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().resolveMethodOn(clazz, method).asSingleResolution();
+ appView.appInfo().resolveMethodOnLegacy(clazz, method).asSingleResolution();
return resolutionResult != null
&& resolutionResult.getResolvedHolder().getType() != method.getHolderType();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
index 8055dc4..16e3dfb 100644
--- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -53,7 +53,10 @@
}
// This is a visibility forward, so check for the direct target.
ProgramMethod targetMethod =
- appView.appInfo().unsafeResolveMethodDueToDexFormat(target).getResolvedProgramMethod();
+ appView
+ .appInfo()
+ .unsafeResolveMethodDueToDexFormatLegacy(target)
+ .getResolvedProgramMethod();
if (targetMethod == null || !targetMethod.getAccessFlags().isPublic()) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
index 150f7ba..d4c83b0 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
@@ -164,7 +164,10 @@
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().unsafeResolveMethodDueToDexFormat(invokedMethod).asSingleResolution();
+ appView
+ .appInfo()
+ .unsafeResolveMethodDueToDexFormatLegacy(invokedMethod)
+ .asSingleResolution();
if (resolutionResult == null) {
// Nothing to propagate; the invoke instruction fails.
return;
@@ -543,7 +546,7 @@
SingleResolutionResult<?> resolution =
appView
.appInfo()
- .resolveMethod(bootstrapMethod.asMethod(), bootstrapMethod.isInterface)
+ .resolveMethodLegacy(bootstrapMethod.asMethod(), bootstrapMethod.isInterface)
.asSingleResolution();
if (resolution != null && resolution.getResolvedHolder().isProgramClass()) {
methodStates.set(resolution.getResolvedProgramMethod(), UnknownMethodState.get());
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index f7f7d06..cd962c3 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -188,7 +188,7 @@
private void registerInvokeMethod(DexMethod method) {
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().unsafeResolveMethodDueToDexFormat(method).asSingleResolution();
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method).asSingleResolution();
if (resolutionResult == null || !resolutionResult.getResolvedHolder().isProgramClass()) {
return;
}
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 b41cdda..675bff8 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
@@ -131,7 +131,7 @@
interfaceState.forEach(
(interfaceMethod, interfaceMethodState) -> {
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(subclass, interfaceMethod);
+ appView.appInfo().resolveMethodOnClassLegacy(subclass, interfaceMethod);
if (resolutionResult.isFailedResolution()) {
// TODO(b/190154391): Do we need to propagate argument information to the first
// virtual method above the inaccessible method in the class hierarchy?
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 59d8ba7..a1aec5a 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
@@ -60,9 +60,6 @@
// memory usage, but would require visiting all transitive (program) super classes for each
// subclass.
private void addParentState(DexProgramClass clazz, DexProgramClass superclass) {
- ClassTypeElement classType =
- TypeElement.fromDexType(clazz.getType(), maybeNull(), appView).asClassType();
-
PropagationState parentState = propagationStates.get(superclass.asProgramClass());
assert parentState != null;
@@ -87,7 +84,7 @@
parentState.inactiveUntilUpperBound.forEach(
(bounds, inactiveMethodStates) -> {
ClassTypeElement upperBound = bounds.getDynamicUpperBoundType().asClassType();
- if (upperBound.equalUpToNullability(classType)) {
+ if (shouldActivateMethodStateGuardedByBounds(upperBound, clazz, superclass)) {
// The upper bound is the current class, thus this inactive information now becomes
// active.
if (bounds.hasDynamicLowerBoundType()) {
@@ -103,7 +100,10 @@
inactiveMethodStates.forEach(
(signature, methodState) -> {
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().resolveMethodOn(clazz, signature).asSingleResolution();
+ appView
+ .appInfo()
+ .resolveMethodOnLegacy(clazz, signature)
+ .asSingleResolution();
// Find the first virtual method in the super class hierarchy.
while (resolutionResult != null
@@ -111,7 +111,7 @@
resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(
+ .resolveMethodOnClassLegacy(
resolutionResult.getResolvedHolder().getSuperType(), signature)
.asSingleResolution();
}
@@ -158,6 +158,20 @@
}
return methodState;
}
+
+ private boolean shouldActivateMethodStateGuardedByBounds(
+ ClassTypeElement upperBound, DexProgramClass currentClass, DexProgramClass superClass) {
+ ClassTypeElement classType =
+ TypeElement.fromDexType(currentClass.getType(), maybeNull(), appView).asClassType();
+ // When propagating argument information for interface methods downwards from an interface to
+ // a non-interface we need to account for the parent classes of the current class.
+ if (superClass.isInterface()
+ && !currentClass.isInterface()
+ && currentClass.getSuperType() != appView.dexItemFactory().objectType) {
+ return classType.lessThanOrEqualUpToNullability(upperBound, appView);
+ }
+ return classType.equalUpToNullability(upperBound);
+ }
}
// For each class, stores the argument information for each virtual method on this class and all
@@ -224,7 +238,7 @@
// TODO(b/190154391): Verify that the bounds are not trivial according to the
// static receiver type.
ClassTypeElement upperBound = bounds.getDynamicUpperBoundType().asClassType();
- if (isUpperBoundSatisfied(upperBound, clazz, propagationState)) {
+ if (isUpperBoundSatisfied(upperBound, clazz)) {
if (bounds.hasDynamicLowerBoundType()) {
// TODO(b/190154391): Verify that the lower bound is a subtype of the current
// class.
@@ -255,10 +269,7 @@
propagationStates.put(clazz, propagationState);
}
- private boolean isUpperBoundSatisfied(
- ClassTypeElement upperBound,
- DexProgramClass currentClass,
- PropagationState propagationState) {
+ private boolean isUpperBoundSatisfied(ClassTypeElement upperBound, DexProgramClass currentClass) {
DexType upperBoundType =
upperBound.getClassType() == appView.dexItemFactory().objectType
&& upperBound.getInterfaces().hasSingleKnownInterface()
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
index 87f26e7..f872fd7 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
@@ -127,7 +127,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .unsafeResolveMethodDueToDexFormat(invoke.getInvokedMethod())
+ .unsafeResolveMethodDueToDexFormatLegacy(invoke.getInvokedMethod())
.asSingleResolution();
if (resolutionResult == null
|| !resolutionResult.getResolvedHolder().isProgramClass()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/unusedarguments/EffectivelyUnusedArgumentsAnalysis.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/unusedarguments/EffectivelyUnusedArgumentsAnalysis.java
index b0be28f..2bc10c5 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/unusedarguments/EffectivelyUnusedArgumentsAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/unusedarguments/EffectivelyUnusedArgumentsAnalysis.java
@@ -150,7 +150,7 @@
ProgramMethod resolvedMethod =
appView
.appInfo()
- .unsafeResolveMethodDueToDexFormat(invoke.getInvokedMethod())
+ .unsafeResolveMethodDueToDexFormatLegacy(invoke.getInvokedMethod())
.getResolvedProgramMethod();
if (resolvedMethod == null || isUnoptimizable(resolvedMethod)) {
return null;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/DepthFirstTopDownClassHierarchyTraversal.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/DepthFirstTopDownClassHierarchyTraversal.java
index 14d47ac..cc81166 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/DepthFirstTopDownClassHierarchyTraversal.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/DepthFirstTopDownClassHierarchyTraversal.java
@@ -84,7 +84,11 @@
}
public boolean isRoot(DexProgramClass clazz) {
- DexProgramClass superclass = asProgramClassOrNull(appView.definitionFor(clazz.getSuperType()));
+ DexType superType = clazz.getSuperType();
+ if (superType == null) {
+ return true;
+ }
+ DexProgramClass superclass = asProgramClassOrNull(appView.definitionFor(superType));
if (superclass != null) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index 1bd92a3..f640d08 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -166,7 +166,7 @@
DexEncodedMethod definition = subclass.lookupVirtualMethod(method);
if (definition == null) {
DexEncodedMethod resolutionTarget =
- appView.appInfo().resolveMethodOnClass(subclass, method).getSingleTarget();
+ appView.appInfo().resolveMethodOnClassLegacy(subclass, method).getSingleTarget();
if (resolutionTarget == null || resolutionTarget.isAbstract()) {
// The fact that this class does not declare the bridge (or the bridge is abstract) should
// not prevent us from hoisting the bridge.
@@ -228,7 +228,7 @@
// The targeted method must be present on the new holder class for this to be feasible.
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(clazz, methodToInvoke);
+ appView.appInfo().resolveMethodOnClassLegacy(clazz, methodToInvoke);
if (!resolutionResult.isSingleResolution()) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
new file mode 100644
index 0000000..7572341
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
@@ -0,0 +1,90 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.interfaces.analysis;
+
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import java.util.function.Function;
+
+public class BottomCfFrameState extends CfFrameState {
+
+ private static final BottomCfFrameState INSTANCE = new BottomCfFrameState();
+
+ private BottomCfFrameState() {}
+
+ static BottomCfFrameState getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState pop() {
+ return error();
+ }
+
+ @Override
+ public CfFrameState pop(Function<FrameType, CfFrameState> fn) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState pop(AppView<?> appView, FrameType expectedType) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState pop(
+ AppView<?> appView, FrameType expectedType, Function<FrameType, CfFrameState> fn) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState pop(AppView<?> appView, FrameType... expectedTypes) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState popAndInitialize(
+ AppView<?> appView, DexMethod constructor, ProgramMethod context) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState popInitialized(AppView<?> appView, DexType expectedType) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState popInitialized(AppView<?> appView, DexType... expectedTypes) {
+ return error();
+ }
+
+ @Override
+ public CfFrameState push(DexType type) {
+ return new ConcreteCfFrameState().push(type);
+ }
+
+ @Override
+ public CfFrameState push(FrameType frameType) {
+ return new ConcreteCfFrameState().push(frameType);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return this == other;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
new file mode 100644
index 0000000..ec899a2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.interfaces.analysis;
+
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractState;
+import java.util.function.Function;
+
+public abstract class CfFrameState extends AbstractState<CfFrameState> {
+
+ public static CfFrameState bottom() {
+ return BottomCfFrameState.getInstance();
+ }
+
+ public static ErroneousCfFrameState error() {
+ return ErroneousCfFrameState.getInstance();
+ }
+
+ @Override
+ public CfFrameState asAbstractState() {
+ return this;
+ }
+
+ public abstract CfFrameState markInitialized(
+ FrameType uninitializedType, DexType initializedType);
+
+ public abstract CfFrameState pop();
+
+ public abstract CfFrameState pop(Function<FrameType, CfFrameState> fn);
+
+ public abstract CfFrameState pop(AppView<?> appView, FrameType expectedType);
+
+ public abstract CfFrameState pop(
+ AppView<?> appView, FrameType expectedType, Function<FrameType, CfFrameState> fn);
+
+ public abstract CfFrameState pop(AppView<?> appView, FrameType... expectedTypes);
+
+ public abstract CfFrameState popAndInitialize(
+ AppView<?> appView, DexMethod constructor, ProgramMethod context);
+
+ public abstract CfFrameState popInitialized(AppView<?> appView, DexType expectedType);
+
+ public abstract CfFrameState popInitialized(AppView<?> appView, DexType... expectedTypes);
+
+ public abstract CfFrameState push(DexType type);
+
+ public abstract CfFrameState push(FrameType frameType);
+
+ @Override
+ public final CfFrameState join(CfFrameState state) {
+ // TODO(b/214496607): Implement join.
+ throw new Unimplemented();
+ }
+
+ @Override
+ public abstract boolean equals(Object other);
+
+ @Override
+ public abstract int hashCode();
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
new file mode 100644
index 0000000..feed0d2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
@@ -0,0 +1,76 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.interfaces.analysis;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+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.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractTransferFunction;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.DataflowAnalysisResult;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.TransferFunctionResult;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfBlock;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfControlFlowGraph;
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfIntraproceduralDataflowAnalysis;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public class CfOpenClosedInterfacesAnalysis {
+
+ private final AppView<AppInfoWithLiveness> appView;
+
+ public CfOpenClosedInterfacesAnalysis(AppView<AppInfoWithLiveness> appView) {
+ this.appView = appView;
+ }
+
+ public void run() {
+ // TODO(b/214496607): Parallelize the analysis.
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ clazz.forEachProgramMethodMatching(DexEncodedMethod::hasCode, this::processMethod);
+ }
+ }
+
+ private void processMethod(ProgramMethod method) {
+ Code code = method.getDefinition().getCode();
+ if (!code.isCfCode()) {
+ assert code.isDefaultInstanceInitializerCode() || code.isThrowNullCode();
+ return;
+ }
+
+ CfCode cfCode = code.asCfCode();
+ CfControlFlowGraph cfg = CfControlFlowGraph.create(cfCode);
+ CfIntraproceduralDataflowAnalysis<CfFrameState> analysis =
+ new CfIntraproceduralDataflowAnalysis<>(
+ CfFrameState.bottom(), cfg, new TransferFunction(method));
+ DataflowAnalysisResult result = analysis.run(cfg.getEntryBlock());
+ // TODO(b/214496607): Determine open interfaces.
+ }
+
+ private class TransferFunction
+ implements AbstractTransferFunction<CfBlock, CfInstruction, CfFrameState> {
+
+ private final ProgramMethod context;
+
+ TransferFunction(ProgramMethod context) {
+ this.context = context;
+ }
+
+ @Override
+ public TransferFunctionResult<CfFrameState> apply(
+ CfInstruction instruction, CfFrameState state) {
+ return instruction.evaluate(state, context, appView, appView.dexItemFactory());
+ }
+
+ @Override
+ public CfFrameState computeBlockEntryState(
+ CfBlock cfBlock, CfBlock predecessor, CfFrameState predecessorExitState) {
+ // TODO(b/214496607): Implement this.
+ throw new Unimplemented();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
new file mode 100644
index 0000000..63654b3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
@@ -0,0 +1,169 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.interfaces.analysis;
+
+import static com.android.tools.r8.cf.code.CfFrame.getInitializedFrameType;
+
+import com.android.tools.r8.cf.code.CfAssignability;
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Objects;
+import java.util.function.Function;
+
+public class ConcreteCfFrameState extends CfFrameState {
+
+ private final Int2ObjectSortedMap<FrameType> locals;
+ private final Deque<FrameType> stack;
+
+ ConcreteCfFrameState() {
+ this(new Int2ObjectAVLTreeMap<>(), new ArrayDeque<>());
+ }
+
+ ConcreteCfFrameState(Int2ObjectSortedMap<FrameType> locals, Deque<FrameType> stack) {
+ this.locals = locals;
+ this.stack = stack;
+ }
+
+ @Override
+ public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
+ if (uninitializedType.isInitialized()) {
+ return error();
+ }
+ for (Int2ObjectMap.Entry<FrameType> entry : locals.int2ObjectEntrySet()) {
+ FrameType frameType = entry.getValue();
+ FrameType initializedFrameType =
+ getInitializedFrameType(uninitializedType, frameType, initializedType);
+ entry.setValue(initializedFrameType);
+ }
+ // TODO(b/214496607): By using a collection that supports element replacement this could mutate
+ // the existing stack instead of building a new one.
+ Deque<FrameType> newStack = new ArrayDeque<>();
+ for (FrameType frameType : stack) {
+ FrameType initializedFrameType =
+ getInitializedFrameType(uninitializedType, frameType, initializedType);
+ newStack.addLast(initializedFrameType);
+ }
+ return new ConcreteCfFrameState(locals, newStack);
+ }
+
+ @Override
+ public CfFrameState pop() {
+ if (stack.isEmpty()) {
+ return error();
+ }
+ stack.removeLast();
+ return this;
+ }
+
+ @Override
+ public CfFrameState pop(Function<FrameType, CfFrameState> fn) {
+ if (stack.isEmpty()) {
+ return error();
+ }
+ FrameType frameType = stack.removeLast();
+ return fn.apply(frameType);
+ }
+
+ @Override
+ public CfFrameState pop(AppView<?> appView, FrameType expectedType) {
+ return pop(appView, expectedType, ignore -> this);
+ }
+
+ @Override
+ public CfFrameState pop(
+ AppView<?> appView, FrameType expectedType, Function<FrameType, CfFrameState> fn) {
+ return pop(
+ frameType ->
+ CfAssignability.isAssignable(frameType, expectedType, appView)
+ ? fn.apply(frameType)
+ : error());
+ }
+
+ @Override
+ public CfFrameState pop(AppView<?> appView, FrameType... expectedTypes) {
+ CfFrameState state = this;
+ for (int i = expectedTypes.length - 1; i >= 0; i--) {
+ state = state.pop(appView, expectedTypes[i]);
+ }
+ return state;
+ }
+
+ @Override
+ public CfFrameState popAndInitialize(
+ AppView<?> appView, DexMethod constructor, ProgramMethod context) {
+ return pop(
+ frameType -> {
+ if (frameType.isUninitializedThis()) {
+ if (constructor.getHolderType() == context.getHolderType()
+ || constructor.getHolderType() == context.getHolder().getSuperType()) {
+ return markInitialized(frameType, context.getHolderType());
+ }
+ } else if (frameType.isUninitializedNew()) {
+ DexType uninitializedNewType = frameType.getUninitializedNewType();
+ if (constructor.getHolderType() == uninitializedNewType) {
+ return markInitialized(frameType, uninitializedNewType);
+ }
+ }
+ return error();
+ });
+ }
+
+ @Override
+ public CfFrameState popInitialized(AppView<?> appView, DexType expectedType) {
+ return pop(
+ frameType ->
+ frameType.isInitialized()
+ && CfAssignability.isAssignable(
+ frameType.getInitializedType(), expectedType, appView)
+ ? this
+ : error());
+ }
+
+ @Override
+ public CfFrameState popInitialized(AppView<?> appView, DexType... expectedTypes) {
+ CfFrameState state = this;
+ for (int i = expectedTypes.length - 1; i >= 0; i--) {
+ state = state.popInitialized(appView, expectedTypes[i]);
+ }
+ return state;
+ }
+
+ @Override
+ public CfFrameState push(DexType type) {
+ return push(FrameType.initialized(type));
+ }
+
+ @Override
+ public CfFrameState push(FrameType frameType) {
+ stack.push(frameType);
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ // TODO(b/214496607): FrameType should implement equals() and hashCode().
+ ConcreteCfFrameState that = (ConcreteCfFrameState) o;
+ return locals.equals(that.locals) && stack.equals(that.stack);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(locals, stack);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
new file mode 100644
index 0000000..7e71f93
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.interfaces.analysis;
+
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import java.util.function.Function;
+
+/** An analysis state representing that the code does not type check. */
+public class ErroneousCfFrameState extends CfFrameState {
+
+ private static final ErroneousCfFrameState INSTANCE = new ErroneousCfFrameState();
+
+ private ErroneousCfFrameState() {}
+
+ static ErroneousCfFrameState getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState pop() {
+ return this;
+ }
+
+ @Override
+ public CfFrameState pop(Function<FrameType, CfFrameState> fn) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState pop(AppView<?> appView, FrameType expectedType) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState pop(
+ AppView<?> appView, FrameType expectedType, Function<FrameType, CfFrameState> fn) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState pop(AppView<?> appView, FrameType... expectedTypes) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState popAndInitialize(
+ AppView<?> appView, DexMethod constructor, ProgramMethod context) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState popInitialized(AppView<?> appView, DexType expectedType) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState popInitialized(AppView<?> appView, DexType... expectedTypes) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState push(DexType type) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState push(FrameType frameType) {
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return this == other;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
index e17be11..63f4483 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
@@ -160,7 +160,7 @@
appView.definitionFor(method.getHolder().getSuperType(), method.getHolder());
if (superClass != null) {
registry.registerMemberAccess(
- appView.appInfo().resolveMethodOn(superClass, method.getReference()));
+ appView.appInfo().resolveMethodOnLegacy(superClass, method.getReference()));
}
// Trace the references in the method and method parameter annotations.
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 1339cbf..e5d00a9 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -108,7 +108,8 @@
}
public ProgramMethod registerMethodReference(DexMethod method) {
- MethodResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method);
+ MethodResolutionResult resolutionResult =
+ appInfo.unsafeResolveMethodDueToDexFormatLegacy(method);
registerMemberAccess(resolutionResult, false);
return resolutionResult.isSingleResolution()
? resolutionResult.asSingleResolution().getResolvedProgramMethod()
@@ -209,7 +210,7 @@
@Override
public void registerInvokeVirtual(DexMethod invokedMethod) {
registerMemberAccessForInvoke(
- appInfo.resolveMethod(
+ appInfo.resolveMethodLegacy(
graphLens.lookupInvokeVirtual(invokedMethod, methodContext, codeLens).getReference(),
false));
}
@@ -217,21 +218,21 @@
@Override
public void registerInvokeDirect(DexMethod invokedMethod) {
registerMemberAccessForInvoke(
- appInfo.unsafeResolveMethodDueToDexFormat(
+ appInfo.unsafeResolveMethodDueToDexFormatLegacy(
graphLens.lookupInvokeDirect(invokedMethod, methodContext, codeLens).getReference()));
}
@Override
public void registerInvokeStatic(DexMethod invokedMethod) {
registerMemberAccessForInvoke(
- appInfo.unsafeResolveMethodDueToDexFormat(
+ appInfo.unsafeResolveMethodDueToDexFormatLegacy(
graphLens.lookupInvokeStatic(invokedMethod, methodContext, codeLens).getReference()));
}
@Override
public void registerInvokeInterface(DexMethod invokedMethod) {
registerMemberAccessForInvoke(
- appInfo.resolveMethod(
+ appInfo.resolveMethodLegacy(
graphLens.lookupInvokeInterface(invokedMethod, methodContext, codeLens).getReference(),
true));
}
@@ -239,7 +240,7 @@
@Override
public void registerInvokeSuper(DexMethod invokedMethod) {
registerMemberAccessForInvoke(
- appInfo.unsafeResolveMethodDueToDexFormat(
+ appInfo.unsafeResolveMethodDueToDexFormatLegacy(
graphLens.lookupInvokeSuper(invokedMethod, methodContext, codeLens).getReference()));
}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index 82a04e6..890e4d3 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -222,7 +222,7 @@
resultsForLine.add(Pair.create(retracedElement, currentList.get()));
contexts.add(retracedElement.getContext());
} else {
- currentList.empty();
+ currentList.clear();
}
}
if (currentList.isSet()) {
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java
index 279a038..d42da83 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java
@@ -4,8 +4,11 @@
package com.android.tools.r8.retrace.internal;
+import static com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.LineParserState.COMPLETE_CLASS_MAPPING;
+import static com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.LineParserState.IS_COMMENT_SOURCE_FILE;
import static java.lang.Integer.MAX_VALUE;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.LineReader;
import java.io.IOException;
import java.io.InputStream;
@@ -15,12 +18,182 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
+import java.util.Set;
public abstract class ProguardMapReaderWithFiltering implements LineReader {
+ // The LineParserState encodes a simple state that the line parser can be in, where the
+ // (successful) transitions allowed are:
+
+ // BEGINNING -> BEGINNING_NO_WHITESPACE -> SEEN_ORIGINAL_CLASS || IS_COMMENT_START
+
+ // IS_COMMENT_START -> IS_COMMENT_SOURCE_FILE
+
+ // SEEN_ORIGINAL_CLASS -> SEEN_ARROW -> SEEN_OBFUSCATED_CLASS -> COMPLETE_CLASS_MAPPING
+ //
+ // From all states there is a transition on invalid input to NOT_CLASS_MAPPING_OR_SOURCE_FILE.
+ // The terminal states are:
+ // { IS_COMMENT_SOURCE_FILE, COMPLETE_CLASS_MAPPING, NOT_CLASS_MAPPING_OR_SOURCE_FILE }
+ //
+ public enum LineParserState {
+ BEGINNING,
+ BEGINNING_NO_WHITESPACE,
+ SEEN_ORIGINAL_CLASS,
+ SEEN_ARROW,
+ SEEN_OBFUSCATED_CLASS,
+ COMPLETE_CLASS_MAPPING,
+ IS_COMMENT_START,
+ IS_COMMENT_SOURCE_FILE,
+ NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+
+ private boolean isTerminal() {
+ return this == NOT_CLASS_MAPPING_OR_SOURCE_FILE
+ || this == COMPLETE_CLASS_MAPPING
+ || this == IS_COMMENT_SOURCE_FILE;
+ }
+
+ private static int currentIndex;
+ private static int endIndex;
+ private static byte[] bytes;
+ private static final byte[] SOURCE_FILE_BYTES = "sourceFile".getBytes();
+
+ public static LineParserState computeState(byte[] bytes, int startIndex, int endIndex) {
+ currentIndex = startIndex;
+ LineParserState.endIndex = endIndex;
+ LineParserState.bytes = bytes;
+ LineParserState currentState = BEGINNING;
+ while (!currentState.isTerminal()) {
+ currentState = currentState.computeNextState();
+ }
+ return currentState;
+ }
+
+ private LineParserState computeNextState() {
+ assert this != NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ switch (this) {
+ case BEGINNING:
+ return readUntilNoWhiteSpace()
+ ? BEGINNING_NO_WHITESPACE
+ : NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ case BEGINNING_NO_WHITESPACE:
+ if (isCommentChar()) {
+ return IS_COMMENT_START;
+ } else {
+ int readLength = readCharactersNoWhiteSpaceUntil(' ');
+ return readLength > 0 ? SEEN_ORIGINAL_CLASS : NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ }
+ case SEEN_ORIGINAL_CLASS:
+ return readArrow() ? SEEN_ARROW : NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ case SEEN_ARROW:
+ int colonIndex = readCharactersNoWhiteSpaceUntil(':');
+ return colonIndex > 0 ? SEEN_OBFUSCATED_CLASS : NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ case SEEN_OBFUSCATED_CLASS:
+ boolean read = readColon();
+ if (!read) {
+ return NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ }
+ boolean noWhiteSpace = readUntilNoWhiteSpace();
+ return (!noWhiteSpace || isCommentChar())
+ ? COMPLETE_CLASS_MAPPING
+ : NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ case IS_COMMENT_START:
+ if (readCharactersUntil('{')
+ && readCharactersUntil(':')
+ && readSingleOrDoubleQuote()
+ && readSourceFile()) {
+ return IS_COMMENT_SOURCE_FILE;
+ } else {
+ return NOT_CLASS_MAPPING_OR_SOURCE_FILE;
+ }
+ default:
+ assert isTerminal();
+ throw new Unreachable("Should not compute next state on terminal state");
+ }
+ }
+
+ private boolean readColon() {
+ return read(':');
+ }
+
+ private boolean readCharactersUntil(char ch) {
+ while (currentIndex < endIndex) {
+ if (bytes[currentIndex++] == ch) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int readCharactersNoWhiteSpaceUntil(char ch) {
+ int startIndex = currentIndex;
+ while (currentIndex < endIndex) {
+ byte readByte = bytes[currentIndex];
+ if (readByte == ch) {
+ return currentIndex - startIndex;
+ }
+ if (Character.isWhitespace(readByte)) {
+ return -1;
+ }
+ currentIndex++;
+ }
+ return -1;
+ }
+
+ private boolean readUntilNoWhiteSpace() {
+ while (currentIndex < endIndex) {
+ if (!Character.isWhitespace(bytes[currentIndex])) {
+ return true;
+ }
+ currentIndex++;
+ }
+ return false;
+ }
+
+ private boolean readArrow() {
+ return readSpace() && read('-') && read('>') && readSpace();
+ }
+
+ private boolean readSpace() {
+ return read(' ');
+ }
+
+ private boolean read(char ch) {
+ return bytes[currentIndex++] == ch;
+ }
+
+ private boolean isCommentChar() {
+ return bytes[currentIndex] == '#';
+ }
+
+ private boolean readSourceFile() {
+ if (endIndex - currentIndex < SOURCE_FILE_BYTES.length) {
+ return false;
+ }
+ int endSourceFileIndex = currentIndex + SOURCE_FILE_BYTES.length;
+ int sourceFileByteIndex = 0;
+ for (; currentIndex < endSourceFileIndex; currentIndex++) {
+ if (SOURCE_FILE_BYTES[sourceFileByteIndex++] != bytes[currentIndex]) {
+ return false;
+ }
+ }
+ return readSingleOrDoubleQuote();
+ }
+
+ private boolean readSingleOrDoubleQuote() {
+ byte readByte = bytes[currentIndex++];
+ return readByte == '\'' || readByte == '"';
+ }
+ }
+
private int startIndex = 0;
private int endIndex = 0;
+ private final Set<String> filter;
+
+ protected ProguardMapReaderWithFiltering(Set<String> filter) {
+ this.filter = filter;
+ }
+
public abstract byte[] read() throws IOException;
public abstract int getStartIndex();
@@ -29,15 +202,43 @@
public abstract boolean exceedsBuffer();
+ private boolean isInsideClassOfInterest = false;
+ private boolean seenFirstClass = false;
+
@Override
public String readLine() throws IOException {
- byte[] bytes = readLineFromMultipleReads();
- if (bytes == null) {
- return null;
+ while (true) {
+ byte[] bytes = readLineFromMultipleReads();
+ if (bytes == null) {
+ return null;
+ }
+ if (filter == null) {
+ return new String(bytes, startIndex, endIndex - startIndex, StandardCharsets.UTF_8);
+ }
+ LineParserState lineParserState = LineParserState.computeState(bytes, startIndex, endIndex);
+ if (lineParserState == COMPLETE_CLASS_MAPPING) {
+ seenFirstClass = true;
+ String classMapping = getBufferAsString(bytes);
+ String obfuscatedClassName = getObfuscatedClassName(classMapping);
+ isInsideClassOfInterest = filter.contains(obfuscatedClassName);
+ return classMapping;
+ } else if (lineParserState == IS_COMMENT_SOURCE_FILE) {
+ return getBufferAsString(bytes);
+ } else if (isInsideClassOfInterest || !seenFirstClass) {
+ return getBufferAsString(bytes);
+ }
}
+ }
+
+ private String getBufferAsString(byte[] bytes) {
return new String(bytes, startIndex, endIndex - startIndex, StandardCharsets.UTF_8);
}
+ private String getObfuscatedClassName(String classMapping) {
+ int arrowIndex = classMapping.indexOf(">");
+ return classMapping.substring(arrowIndex + 2, classMapping.length() - 1);
+ }
+
private byte[] readLineFromMultipleReads() throws IOException {
startIndex = 0;
endIndex = 0;
@@ -82,7 +283,9 @@
private int currentPosition = 0;
private int temporaryBufferPosition = 0;
- public ProguardMapReaderWithFilteringMappedBuffer(Path mappingFile) throws IOException {
+ public ProguardMapReaderWithFilteringMappedBuffer(
+ Path mappingFile, Set<String> classNamesOfInterest) throws IOException {
+ super(classNamesOfInterest);
fileChannel = FileChannel.open(mappingFile, StandardOpenOption.READ);
channelSize = fileChannel.size();
readFromChannel();
@@ -160,7 +363,9 @@
private int endIndex = 0;
private int endReadIndex = 0;
- public ProguardMapReaderWithFilteringInputBuffer(InputStream inputStream) {
+ public ProguardMapReaderWithFilteringInputBuffer(
+ InputStream inputStream, Set<String> classNamesOfInterest) {
+ super(classNamesOfInterest);
this.inputStream = inputStream;
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingProviderBuilderImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingProviderBuilderImpl.java
index cb6991e..a5c1dd6 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingProviderBuilderImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingProviderBuilderImpl.java
@@ -64,17 +64,16 @@
@Override
public ProguardMappingProvider build() {
try {
+ Set<String> buildForClass = allowLookupAllClasses ? null : allowedLookup;
LineReader reader =
proguardMapProducer.isFileBacked()
- ? new ProguardMapReaderWithFilteringMappedBuffer(proguardMapProducer.getPath())
- : new ProguardMapReaderWithFilteringInputBuffer(proguardMapProducer.get());
+ ? new ProguardMapReaderWithFilteringMappedBuffer(
+ proguardMapProducer.getPath(), buildForClass)
+ : new ProguardMapReaderWithFilteringInputBuffer(
+ proguardMapProducer.get(), buildForClass);
return new ProguardMappingProviderImpl(
ClassNameMapper.mapperFromLineReaderWithFiltering(
- reader,
- diagnosticsHandler,
- true,
- allowExperimental,
- allowLookupAllClasses ? null : allowedLookup));
+ reader, diagnosticsHandler, true, allowExperimental, buildForClass));
} catch (Exception e) {
throw new InvalidMappingFileException(e);
}
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 34425b3..5a6ef63 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1388,7 +1388,7 @@
return cachedItem;
}
SingleResolutionResult<?> resolution =
- resolveMethodOn(initialResolutionHolder, method).asSingleResolution();
+ resolveMethodOnLegacy(initialResolutionHolder, method).asSingleResolution();
if (resolution == null
|| resolution.isAccessibleForVirtualDispatchFrom(context.getHolder(), this).isFalse()) {
return null;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 98562f9..47baa0b 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2299,7 +2299,8 @@
private SingleResolutionResult<?> resolveMethod(
DexMethod method, ProgramDefinition context, KeepReason reason) {
// Record the references in case they are not program types.
- MethodResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method);
+ MethodResolutionResult resolutionResult =
+ appInfo.unsafeResolveMethodDueToDexFormatLegacy(method);
if (resolutionResult.isFailedResolution()) {
markFailedMethodResolutionTargets(
method, resolutionResult.asFailedResolution(), context, reason);
@@ -2313,7 +2314,7 @@
private SingleResolutionResult<?> resolveMethod(
DexMethod method, ProgramDefinition context, KeepReason reason, boolean interfaceInvoke) {
// Record the references in case they are not program types.
- MethodResolutionResult resolutionResult = appInfo.resolveMethod(method, interfaceInvoke);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodLegacy(method, interfaceInvoke);
if (resolutionResult.isSingleResolution()) {
recordMethodReference(
method, resolutionResult.getResolutionPair().asProgramDerivedContext(context));
@@ -2794,7 +2795,8 @@
(resolutionSearchKey, contexts) -> {
SingleResolutionResult<?> singleResolution =
appInfo
- .resolveMethod(resolutionSearchKey.method, resolutionSearchKey.isInterface)
+ .resolveMethodLegacy(
+ resolutionSearchKey.method, resolutionSearchKey.isInterface)
.asSingleResolution();
if (singleResolution == null) {
assert false : "Should not be null";
@@ -2859,7 +2861,7 @@
markLibraryOrClasspathOverrideLive(
instantiation,
libraryClass,
- appInfo.resolveMethodOn(libraryClass, method.getReference()));
+ appInfo.resolveMethodOnLegacy(libraryClass, method.getReference()));
// Due to API conversion, some overrides can be hidden since they will be rewritten. See
// class comment of DesugaredLibraryAPIConverter and vivifiedType logic.
@@ -2876,7 +2878,7 @@
markLibraryOrClasspathOverrideLive(
instantiation,
libraryClass,
- appInfo.resolveMethodOn(instantiation.asClass(), methodToResolve));
+ appInfo.resolveMethodOnLegacy(instantiation.asClass(), methodToResolve));
}
}
}
@@ -2941,6 +2943,9 @@
markFieldAsLive(field, clazz, reason);
}
}
+ if (clazz.superType == null) {
+ break;
+ }
clazz = getProgramClassOrNull(clazz.superType, clazz);
} while (clazz != null && !objectAllocationInfoCollection.isInstantiatedDirectly(clazz));
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ObjectAllocationInfoCollectionUtils.java b/src/main/java/com/android/tools/r8/shaking/ObjectAllocationInfoCollectionUtils.java
index b7b2513..a578485 100644
--- a/src/main/java/com/android/tools/r8/shaking/ObjectAllocationInfoCollectionUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/ObjectAllocationInfoCollectionUtils.java
@@ -62,7 +62,8 @@
SingleResolutionResult resolution =
appView
.appInfo()
- .resolveMethodOn(clazz, appView.dexItemFactory().objectMembers.finalize)
+ .resolveMethodOnLegacy(
+ clazz, appView.dexItemFactory().objectMembers.finalize)
.asSingleResolution();
if (resolution != null && resolution.getResolvedHolder().isProgramClass()) {
return TraversalContinuation.doBreak();
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 3b96973..471f865 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -91,6 +91,7 @@
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -129,6 +130,7 @@
private final Map<DexMember<?, ?>, ProguardMemberRule> noSideEffects = new IdentityHashMap<>();
private final Map<DexMember<?, ?>, ProguardMemberRule> assumedValues = new IdentityHashMap<>();
private final Set<DexMember<?, ?>> identifierNameStrings = Sets.newIdentityHashSet();
+ private final Map<DexMethod, ProgramMethod> keptMethodBridges = new ConcurrentHashMap<>();
private final Queue<DelayedRootSetActionItem> delayedRootSetActionItems =
new ConcurrentLinkedQueue<>();
private final InternalOptions options;
@@ -420,7 +422,7 @@
DexEncodedMethod target =
appView
.appInfo()
- .unsafeResolveMethodDueToDexFormat(referenceInSubType)
+ .unsafeResolveMethodDueToDexFormatLegacy(referenceInSubType)
.getSingleTarget();
// But, the resolution should not be landed on the current type we are visiting.
if (target == null || target.getHolderType() == type) {
@@ -574,7 +576,9 @@
visitAllSuperInterfaces(iface);
}
if (!clazz.isInterface()) {
- visitAllSuperInterfaces(clazz.superType);
+ if (clazz.superType != null) {
+ visitAllSuperInterfaces(clazz.superType);
+ }
return;
}
if (originalClazz == clazz) {
@@ -601,7 +605,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOn(originalClazz, method.getReference())
+ .resolveMethodOnLegacy(originalClazz, method.getReference())
.asSingleResolution();
if (resolutionResult == null || !resolutionResult.isVirtualTarget()) {
return;
@@ -614,16 +618,24 @@
// TODO(b/143643942): For fullmode, this check should probably be removed.
return;
}
- ProgramMethod resolutionMethod =
- new ProgramMethod(
- resolutionResult.getResolvedHolder().asProgramClass(),
- resolutionResult.getResolvedMethod());
- ProgramMethod methodToKeep =
- canInsertForwardingMethod(originalClazz, resolutionMethod.getDefinition())
- ? new ProgramMethod(
- originalClazz,
- resolutionMethod.getDefinition().toForwardingMethod(originalClazz, appView))
- : resolutionMethod;
+ ProgramMethod resolutionMethod = resolutionResult.getResolvedProgramMethod();
+ ProgramMethod methodToKeep;
+ if (canInsertForwardingMethod(originalClazz, resolutionMethod.getDefinition())) {
+ DexMethod methodToKeepReference =
+ resolutionMethod.getReference().withHolder(originalClazz, appView.dexItemFactory());
+ methodToKeep =
+ keptMethodBridges.computeIfAbsent(
+ methodToKeepReference,
+ k ->
+ new ProgramMethod(
+ originalClazz,
+ resolutionMethod
+ .getDefinition()
+ .toForwardingMethod(originalClazz, appView)));
+ assert methodToKeepReference.equals(methodToKeep.getReference());
+ } else {
+ methodToKeep = resolutionMethod;
+ }
delayedRootSetActionItems.add(
new InterfaceMethodSyntheticBridgeAction(
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 9797f72..5aa62c3 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -853,7 +853,7 @@
// Conservatively find all possible targets for this method.
LookupResultSuccess lookupResult =
appInfo
- .resolveMethodOnInterface(method.getHolderType(), method.getReference())
+ .resolveMethodOnInterfaceLegacy(method.getHolderType(), method.getReference())
.lookupVirtualDispatchTargets(target, appInfo)
.asLookupResultSuccess();
assert lookupResult != null;
@@ -1568,7 +1568,7 @@
// Returns the method that shadows the given method, or null if method is not shadowed.
private DexEncodedMethod findMethodInTarget(DexEncodedMethod method) {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOn(target, method.getReference());
+ appInfo.resolveMethodOnLegacy(target, method.getReference());
if (!resolutionResult.isSingleResolution()) {
// May happen in case of missing classes, or if multiple implementations were found.
abortMerge = true;
@@ -2133,8 +2133,8 @@
MethodResolutionResult resolutionResult =
isInterface.isUnknown()
- ? appView.appInfo().unsafeResolveMethodDueToDexFormat(method)
- : appView.appInfo().resolveMethod(method, isInterface.isTrue());
+ ? appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method)
+ : appView.appInfo().resolveMethodLegacy(method, isInterface.isTrue());
if (!resolutionResult.isSingleResolution()
|| !resolutionResult.asSingleResolution().getResolvedMethod().isPublic()) {
setResult(true);
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 cee58c4..f6d8354 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -569,7 +569,7 @@
SynthesizingContext outerContext = internalGetOuterContext(context, appView);
DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
DexClass clazz = appView.definitionFor(type);
- assert clazz != null;
+ assert clazz != null : "Missing existing fixed class " + type;
assert isSyntheticClass(type);
assert clazz.isProgramClass();
return clazz.asProgramClass();
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index c5ffc7a..1d74048 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -246,7 +246,7 @@
DexClassAndMethod superTarget =
appInfo()
- .resolveMethodOn(method.getHolder(), method.getReference())
+ .resolveMethodOnLegacy(method.getHolder(), method.getReference())
.lookupInvokeSpecialTarget(method.getHolder(), appInfo());
if (superTarget != null
&& !superTarget.isProgramMethod()
@@ -267,7 +267,8 @@
method -> {
DexClassAndMethod resolvedMethod =
appInfo()
- .resolveMethodOn(superType, method.getReference(), superType != clazz.superType)
+ .resolveMethodOnLegacy(
+ superType, method.getReference(), superType != clazz.superType)
.getResolutionPair();
if (resolvedMethod != null
&& !resolvedMethod.isProgramMethod()
@@ -311,7 +312,7 @@
assert lookupResult.getType().isStatic();
DexMethod rewrittenMethod = lookupResult.getReference();
handleRewrittenMethodResolution(
- rewrittenMethod, appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod));
+ rewrittenMethod, appInfo().unsafeResolveMethodDueToDexFormatLegacy(rewrittenMethod));
}
@Override
@@ -320,7 +321,7 @@
assert lookupResult.getType().isSuper();
DexMethod rewrittenMethod = lookupResult.getReference();
MethodResolutionResult resolutionResult =
- appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod);
+ appInfo().unsafeResolveMethodDueToDexFormatLegacy(rewrittenMethod);
if (resolutionResult.isFailedResolution()
&& resolutionResult.asFailedResolution().hasMethodsCausingError()) {
handleRewrittenMethodResolution(rewrittenMethod, resolutionResult);
@@ -349,8 +350,8 @@
handleRewrittenMethodResolution(
method,
lookupResult.getType().isInterface()
- ? appInfo().resolveMethodOnInterfaceHolder(method)
- : appInfo().resolveMethodOnClassHolder(method));
+ ? appInfo().resolveMethodOnInterfaceHolderLegacy(method)
+ : appInfo().resolveMethodOnClassHolderLegacy(method));
}
private void handleRewrittenMethodResolution(
diff --git a/src/main/java/com/android/tools/r8/utils/Box.java b/src/main/java/com/android/tools/r8/utils/Box.java
index 2e6f17c..1134718 100644
--- a/src/main/java/com/android/tools/r8/utils/Box.java
+++ b/src/main/java/com/android/tools/r8/utils/Box.java
@@ -5,65 +5,43 @@
package com.android.tools.r8.utils;
import java.util.Comparator;
-import java.util.Objects;
import java.util.function.Supplier;
-public class Box<T> {
-
- private T value;
+public class Box<T> extends BoxBase<T> {
public Box() {}
public Box(T initialValue) {
- set(initialValue);
+ super(initialValue);
}
+ @Override
+ public void clear() {
+ super.clear();
+ }
+
+ @Override
public T computeIfAbsent(Supplier<T> supplier) {
- if (value == null) {
- value = supplier.get();
- }
- return value;
+ return super.computeIfAbsent(supplier);
}
+ @Override
public T get() {
- return value;
+ return super.get();
}
- public void set(T value) {
- this.value = value;
- }
-
- public void setMin(T element, Comparator<T> comparator) {
- if (!isSet() || comparator.compare(element, get()) < 0) {
- set(element);
- }
- }
-
- public boolean isSet() {
- return value != null;
- }
-
+ @Override
public T getAndSet(T newValue) {
- T oldValue = value;
- value = newValue;
- return oldValue;
+ return super.getAndSet(newValue);
}
@Override
- public boolean equals(Object object) {
- if (object == null || getClass() != object.getClass()) {
- return false;
- }
- Box<?> box = (Box<?>) object;
- return Objects.equals(value, box.value);
+ public void set(T value) {
+ super.set(value);
}
@Override
- public int hashCode() {
- return Objects.hashCode(value);
- }
-
- public void empty() {
- value = null;
+ public void setMin(T value, Comparator<T> comparator) {
+ super.setMin(value, comparator);
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/BoxBase.java b/src/main/java/com/android/tools/r8/utils/BoxBase.java
new file mode 100644
index 0000000..d38d92b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/BoxBase.java
@@ -0,0 +1,69 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public abstract class BoxBase<T> {
+
+ private T value;
+
+ public BoxBase() {}
+
+ public BoxBase(T initialValue) {
+ set(initialValue);
+ }
+
+ void clear() {
+ set(null);
+ }
+
+ T computeIfAbsent(Supplier<T> supplier) {
+ if (!isSet()) {
+ set(supplier.get());
+ }
+ return value;
+ }
+
+ T get() {
+ return value;
+ }
+
+ T getAndSet(T newValue) {
+ T oldValue = value;
+ value = newValue;
+ return oldValue;
+ }
+
+ void set(T value) {
+ this.value = value;
+ }
+
+ void setMin(T value, Comparator<T> comparator) {
+ if (!isSet() || comparator.compare(value, get()) < 0) {
+ set(value);
+ }
+ }
+
+ public boolean isSet() {
+ return value != null;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ BoxBase<?> box = (BoxBase<?>) object;
+ return Objects.equals(value, box.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(value);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/DepthFirstSearchWorkListBase.java b/src/main/java/com/android/tools/r8/utils/DepthFirstSearchWorkListBase.java
index c9a56da..c16b39f 100644
--- a/src/main/java/com/android/tools/r8/utils/DepthFirstSearchWorkListBase.java
+++ b/src/main/java/com/android/tools/r8/utils/DepthFirstSearchWorkListBase.java
@@ -13,12 +13,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
-public abstract class DepthFirstSearchWorkListBase<N, T extends DFSNodeImpl<N>> {
+public abstract class DepthFirstSearchWorkListBase<N, T extends DFSNodeImpl<N>, TB, TC> {
public interface DFSNode<N> {
N getNode();
@@ -103,36 +104,48 @@
}
private final ArrayDeque<T> workList = new ArrayDeque<>();
+ // This map is necessary ensure termination since we embed nodes into nodes with state.
+ private final Map<N, T> nodeToNodeWithStateMap = new IdentityHashMap<>();
abstract T createDfsNode(N node);
/** The initial processing of a node during forward search */
- abstract TraversalContinuation<?, ?> internalOnVisit(T node);
+ abstract TraversalContinuation<TB, TC> internalOnVisit(T node);
/** The joining of state during backtracking of the algorithm. */
- abstract TraversalContinuation<?, ?> internalOnJoin(T node);
+ abstract TraversalContinuation<TB, TC> internalOnJoin(T node);
+
+ abstract List<TC> getFinalStateForRoots(Collection<N> roots);
final T internalEnqueueNode(N value) {
- T dfsNode = createDfsNode(value);
+ T dfsNode = nodeToNodeWithStateMap.computeIfAbsent(value, this::createDfsNode);
if (dfsNode.isNotProcessed()) {
workList.addLast(dfsNode);
}
return dfsNode;
}
+ protected T getNodeStateForNode(N value) {
+ return nodeToNodeWithStateMap.get(value);
+ }
+
+ public final TraversalContinuation<TB, TC> run(N root) {
+ return run(Collections.singletonList(root)).map(Function.identity(), results -> results.get(0));
+ }
+
@SafeVarargs
- public final TraversalContinuation<?, ?> run(N... roots) {
+ public final TraversalContinuation<TB, List<TC>> run(N... roots) {
return run(Arrays.asList(roots));
}
- public final TraversalContinuation<?, ?> run(Collection<N> roots) {
+ public final TraversalContinuation<TB, List<TC>> run(Collection<N> roots) {
roots.forEach(this::internalEnqueueNode);
- TraversalContinuation<?, ?> continuation = TraversalContinuation.doContinue();
while (!workList.isEmpty()) {
T node = workList.removeLast();
if (node.isFinished()) {
continue;
}
+ TraversalContinuation<TB, TC> continuation;
if (node.isNotProcessed()) {
workList.addLast(node);
node.setWaiting();
@@ -143,14 +156,15 @@
node.setFinished();
}
if (continuation.shouldBreak()) {
- return continuation;
+ return TraversalContinuation.doBreak(continuation.asBreak().getValue());
}
}
- return continuation;
+
+ return TraversalContinuation.doContinue(getFinalStateForRoots(roots));
}
- public abstract static class DepthFirstSearchWorkList<N>
- extends DepthFirstSearchWorkListBase<N, DFSNodeImpl<N>> {
+ public abstract static class DepthFirstSearchWorkList<N, TB, TC>
+ extends DepthFirstSearchWorkListBase<N, DFSNodeImpl<N>, TB, TC> {
/**
* The initial processing of the node when visiting the first time during the depth first
@@ -161,7 +175,7 @@
* before but not finished there is a cycle.
* @return A value describing if the DFS algorithm should continue to run.
*/
- protected abstract TraversalContinuation<?, ?> process(
+ protected abstract TraversalContinuation<TB, TC> process(
DFSNode<N> node, Function<N, DFSNode<N>> childNodeConsumer);
@Override
@@ -170,18 +184,18 @@
}
@Override
- TraversalContinuation<?, ?> internalOnVisit(DFSNodeImpl<N> node) {
+ TraversalContinuation<TB, TC> internalOnVisit(DFSNodeImpl<N> node) {
return process(node, this::internalEnqueueNode);
}
@Override
- protected TraversalContinuation<?, ?> internalOnJoin(DFSNodeImpl<N> node) {
+ protected TraversalContinuation<TB, TC> internalOnJoin(DFSNodeImpl<N> node) {
return TraversalContinuation.doContinue();
}
}
- public abstract static class StatefulDepthFirstSearchWorkList<N, S>
- extends DepthFirstSearchWorkListBase<N, DFSNodeWithStateImpl<N, S>> {
+ public abstract static class StatefulDepthFirstSearchWorkList<N, S, TB>
+ extends DepthFirstSearchWorkListBase<N, DFSNodeWithStateImpl<N, S>, TB, S> {
private final Map<DFSNodeWithStateImpl<N, S>, List<DFSNodeWithState<N, S>>> childStateMap =
new IdentityHashMap<>();
@@ -195,7 +209,7 @@
* before but not finished there is a cycle.
* @return A value describing if the DFS algorithm should continue to run.
*/
- protected abstract TraversalContinuation<?, ?> process(
+ protected abstract TraversalContinuation<TB, S> process(
DFSNodeWithState<N, S> node, Function<N, DFSNodeWithState<N, S>> childNodeConsumer);
/**
@@ -205,7 +219,7 @@
* @param childStates The already computed child states.
* @return A value describing if the DFS algorithm should continue to run.
*/
- protected abstract TraversalContinuation<?, ?> joiner(
+ protected abstract TraversalContinuation<TB, S> joiner(
DFSNodeWithState<N, S> node, List<DFSNodeWithState<N, S>> childStates);
@Override
@@ -214,7 +228,7 @@
}
@Override
- TraversalContinuation<?, ?> internalOnVisit(DFSNodeWithStateImpl<N, S> node) {
+ TraversalContinuation<TB, S> internalOnVisit(DFSNodeWithStateImpl<N, S> node) {
List<DFSNodeWithState<N, S>> childStates = new ArrayList<>();
List<DFSNodeWithState<N, S>> removedChildStates = childStateMap.put(node, childStates);
assert removedChildStates == null;
@@ -228,7 +242,7 @@
}
@Override
- protected TraversalContinuation<?, ?> internalOnJoin(DFSNodeWithStateImpl<N, S> node) {
+ protected TraversalContinuation<TB, S> internalOnJoin(DFSNodeWithStateImpl<N, S> node) {
return joiner(
node,
childStateMap.computeIfAbsent(
@@ -238,5 +252,10 @@
return new ArrayList<>();
}));
}
+
+ @Override
+ List<S> getFinalStateForRoots(Collection<N> roots) {
+ return ListUtils.map(roots, root -> getNodeStateForNode(root).state);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
deleted file mode 100644
index 00412d9..0000000
--- a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright (c) 2018, 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.utils;
-
-import com.android.tools.r8.ArchiveClassFileProvider;
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.Keep;
-import com.android.tools.r8.dexsplitter.DexSplitter.FeatureJar;
-import com.android.tools.r8.origin.PathOrigin;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-/**
- * Provides a mappings of classes to modules. The structure of the input file is as follows:
- * packageOrClass:module
- *
- * <p>Lines with a # prefix are ignored.
- *
- * <p>We will do most specific matching, i.e.,
- * <pre>
- * com.google.foobar.*:feature2
- * com.google.*:base
- * </pre>
- * will put everything in the com.google namespace into base, except classes in com.google.foobar
- * that will go to feature2. Class based mappings takes precedence over packages (since they are
- * more specific):
- * <pre>
- * com.google.A:feature2
- * com.google.*:base
- * </pre>
- * Puts A into feature2, and all other classes from com.google into base.
- *
- * <p>Note that this format does not allow specifying inter-module dependencies, this is simply a
- * placement tool.
- */
-@Keep
-public final class FeatureClassMapping {
-
- Map<String, String> parsedRules = new HashMap<>(); // Already parsed rules.
- Map<String, String> parseNonClassRules = new HashMap<>();
- boolean usesOnlyExactMappings = true;
-
- Set<FeaturePredicate> mappings = new HashSet<>();
-
- Path mappingFile;
- String baseName = DEFAULT_BASE_NAME;
-
- static final String DEFAULT_BASE_NAME = "base";
-
- static final String COMMENT = "#";
- static final String SEPARATOR = ":";
-
- public String getBaseName() {
- return baseName;
- }
-
- private static class SpecificationOrigin extends PathOrigin {
-
- public SpecificationOrigin(Path path) {
- super(path);
- }
-
- @Override
- public String part() {
- return "specification file '" + super.part() + "'";
- }
- }
-
- private static class JarFileOrigin extends PathOrigin {
-
- public JarFileOrigin(Path path) {
- super(path);
- }
-
- @Override
- public String part() {
- return "jar file '" + super.part() + "'";
- }
- }
-
- public static FeatureClassMapping fromSpecification(Path file) throws FeatureMappingException {
- return fromSpecification(file, new DiagnosticsHandler() {});
- }
-
- public static FeatureClassMapping fromSpecification(Path file, DiagnosticsHandler reporter)
- throws FeatureMappingException {
- FeatureClassMapping mapping = new FeatureClassMapping();
- List<String> lines = null;
- try {
- lines = FileUtils.readAllLines(file);
- } catch (IOException e) {
- ExceptionDiagnostic error = new ExceptionDiagnostic(e, new SpecificationOrigin(file));
- reporter.error(error);
- throw new AbortException(error);
- }
- for (int i = 0; i < lines.size(); i++) {
- String line = lines.get(i);
- mapping.parseAndAdd(line, i);
- }
- return mapping;
- }
-
- public static class Internal {
- private static List<String> getClassFileDescriptors(String jar, DiagnosticsHandler reporter) {
- Path jarPath = Paths.get(jar);
- try {
- return new ArchiveClassFileProvider(jarPath).getClassDescriptors()
- .stream()
- .map(DescriptorUtils::descriptorToJavaType)
- .collect(Collectors.toList());
- } catch (IOException e) {
- ExceptionDiagnostic error = new ExceptionDiagnostic(e, new JarFileOrigin(jarPath));
- reporter.error(error);
- throw new AbortException(error);
- }
- }
-
- private static List<String> getNonClassFiles(String jar, DiagnosticsHandler reporter) {
- try (ZipFile zipfile = new ZipFile(jar, StandardCharsets.UTF_8)) {
- return zipfile.stream()
- .filter(entry -> !ZipUtils.isClassFile(entry.getName()))
- .map(ZipEntry::getName)
- .collect(Collectors.toList());
- } catch (IOException e) {
- ExceptionDiagnostic error = new ExceptionDiagnostic(e, new JarFileOrigin(Paths.get(jar)));
- reporter.error(error);
- throw new AbortException(error);
- }
- }
-
- public static FeatureClassMapping fromJarFiles(
- List<FeatureJar> featureJars, List<String> baseJars, String baseName,
- DiagnosticsHandler reporter)
- throws FeatureMappingException {
- FeatureClassMapping mapping = new FeatureClassMapping();
- if (baseName != null) {
- mapping.baseName = baseName;
- }
- for (FeatureJar featureJar : featureJars) {
- for (String javaType : getClassFileDescriptors(featureJar.getJar(), reporter)) {
- mapping.addMapping(javaType, featureJar.getOutputName());
- }
- for (String nonClass : getNonClassFiles(featureJar.getJar(), reporter)) {
- mapping.addNonClassMapping(nonClass, featureJar.getOutputName());
- }
- }
- for (String baseJar : baseJars) {
- for (String javaType : getClassFileDescriptors(baseJar, reporter)) {
- mapping.addBaseMapping(javaType);
- }
- for (String nonClass : getNonClassFiles(baseJar, reporter)) {
- mapping.addBaseNonClassMapping(nonClass);
- }
- }
- assert mapping.usesOnlyExactMappings;
- return mapping;
- }
-
- }
-
- private FeatureClassMapping() {}
-
- public void addBaseMapping(String clazz) throws FeatureMappingException {
- addMapping(clazz, baseName);
- }
-
- public void addBaseNonClassMapping(String name) {
- addNonClassMapping(name, baseName);
- }
-
- public void addMapping(String clazz, String feature) throws FeatureMappingException {
- addRule(clazz, feature, 0);
- }
-
- public void addNonClassMapping(String name, String feature) {
- // If a non-class file is present in multiple features put the resource in the base.
- parseNonClassRules.put(name, parseNonClassRules.containsKey(name) ? baseName : feature);
- }
-
- FeatureClassMapping(List<String> lines) throws FeatureMappingException {
- for (int i = 0; i < lines.size(); i++) {
- String line = lines.get(i);
- parseAndAdd(line, i);
- }
- }
-
- public String featureForClass(String clazz) {
- if (usesOnlyExactMappings) {
- return parsedRules.getOrDefault(clazz, baseName);
- } else {
- FeaturePredicate bestMatch = null;
- for (FeaturePredicate mapping : mappings) {
- if (mapping.match(clazz)) {
- if (bestMatch == null || bestMatch.predicate.length() < mapping.predicate.length()) {
- bestMatch = mapping;
- }
- }
- }
- if (bestMatch == null) {
- return baseName;
- }
- return bestMatch.feature;
- }
- }
-
- public String featureForNonClass(String nonClass) {
- return parseNonClassRules.getOrDefault(nonClass, baseName);
- }
-
- private void parseAndAdd(String line, int lineNumber) throws FeatureMappingException {
- if (line.startsWith(COMMENT)) {
- return; // Ignore comments
- }
- if (line.isEmpty()) {
- return; // Ignore blank lines
- }
-
- if (!line.contains(SEPARATOR)) {
- error("Mapping lines must contain a " + SEPARATOR, lineNumber);
- }
- String[] values = line.split(SEPARATOR);
- if (values.length != 2) {
- error("Mapping lines can only contain one " + SEPARATOR, lineNumber);
- }
-
- String predicate = values[0];
- String feature = values[1];
- addRule(predicate, feature, lineNumber);
- }
-
- private void addRule(String predicate, String feature, int lineNumber)
- throws FeatureMappingException {
- if (parsedRules.containsKey(predicate)) {
- if (!parsedRules.get(predicate).equals(feature)) {
- error("Redefinition of predicate " + predicate + "not allowed", lineNumber);
- }
- return; // Already have this rule.
- }
- parsedRules.put(predicate, feature);
- FeaturePredicate featurePredicate = new FeaturePredicate(predicate, feature);
- mappings.add(featurePredicate);
- usesOnlyExactMappings &= featurePredicate.isExactmapping();
- }
-
- private void error(String error, int line) throws FeatureMappingException {
- throw new FeatureMappingException(
- "Invalid mappings specification: " + error + "\n in file " + mappingFile + ":" + line);
- }
-
- @Keep
- public static class FeatureMappingException extends Exception {
- FeatureMappingException(String message) {
- super(message);
- }
- }
-
- /** A feature predicate can either be a wildcard or class predicate. */
- private static class FeaturePredicate {
- private static Pattern identifier = Pattern.compile("[A-Za-z_\\-][A-Za-z0-9_$\\-]*");
- final String predicate;
- final String feature;
- final boolean isCatchAll;
- // False implies class predicate.
- final boolean isWildcard;
-
- FeaturePredicate(String predicate, String feature) throws FeatureMappingException {
- isWildcard = predicate.endsWith(".*");
- isCatchAll = predicate.equals("*");
- if (isCatchAll) {
- this.predicate = "";
- } else if (isWildcard) {
- String packageName = predicate.substring(0, predicate.length() - 2);
- if (!DescriptorUtils.isValidJavaType(packageName)) {
- throw new FeatureMappingException(packageName + " is not a valid identifier");
- }
- // Prefix of a fully-qualified class name, including a terminating dot.
- this.predicate = predicate.substring(0, predicate.length() - 1);
- } else {
- if (!DescriptorUtils.isValidJavaType(predicate)) {
- throw new FeatureMappingException(predicate + " is not a valid identifier");
- }
- this.predicate = predicate;
- }
- this.feature = feature;
- }
-
- boolean match(String className) {
- if (isCatchAll) {
- return true;
- } else if (isWildcard) {
- return className.startsWith(predicate);
- } else {
- return className.equals(predicate);
- }
- }
-
- boolean isExactmapping() {
- return !isWildcard && !isCatchAll;
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/utils/IntBox.java b/src/main/java/com/android/tools/r8/utils/IntBox.java
index 9a31ebd..79684cd 100644
--- a/src/main/java/com/android/tools/r8/utils/IntBox.java
+++ b/src/main/java/com/android/tools/r8/utils/IntBox.java
@@ -53,6 +53,15 @@
value += i;
}
+ public int incrementAndGet() {
+ return incrementAndGet(1);
+ }
+
+ public int incrementAndGet(int i) {
+ increment(i);
+ return get();
+ }
+
public void set(int value) {
this.value = value;
}
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 8942e41..a2c6aae 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -360,6 +360,7 @@
public boolean enableRedundantFieldLoadElimination = true;
// TODO(b/138917494): Disable until we have numbers on potential performance penalties.
public boolean enableRedundantConstNumberOptimization = false;
+ public boolean enableLoopUnrolling = true;
public String synthesizedClassPrefix = "";
@@ -1671,6 +1672,10 @@
public void disableApiCallerIdentification() {
enableApiCallerIdentification = false;
}
+
+ public void disableSubbingOfClasses() {
+ enableStubbingOfClasses = false;
+ }
}
public static class ProtoShrinkingOptions {
@@ -1815,7 +1820,6 @@
public boolean enableEnumUnboxingDebugLogs = false;
public boolean forceRedundantConstNumberRemoval = false;
public boolean enableExperimentalDesugaredLibraryKeepRuleGenerator = false;
- public boolean enableExperimentalLoopUnrolling = false;
public boolean invertConditionals = false;
public boolean placeExceptionalBlocksLast = false;
public boolean dontCreateMarkerInD8 = false;
diff --git a/src/main/java/com/android/tools/r8/utils/LazyBox.java b/src/main/java/com/android/tools/r8/utils/LazyBox.java
index 38d1f2a..0a25b99 100644
--- a/src/main/java/com/android/tools/r8/utils/LazyBox.java
+++ b/src/main/java/com/android/tools/r8/utils/LazyBox.java
@@ -6,7 +6,7 @@
import java.util.function.Supplier;
-public class LazyBox<T> extends Box<T> {
+public class LazyBox<T> extends BoxBase<T> {
private final Supplier<T> supplier;
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 78f612a..f277168 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -72,7 +72,6 @@
import com.android.tools.r8.retrace.internal.RetraceUtils;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
-import com.google.common.base.Suppliers;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
@@ -87,7 +86,6 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Function;
-import java.util.function.Supplier;
public class LineNumberOptimizer {
@@ -502,8 +500,8 @@
// Create a supplier which creates a new, cached ClassNaming.Builder on-demand.
DexType originalType = appView.graphLens().getOriginalType(clazz.type);
DexString renamedDescriptor = namingLens.lookupDescriptor(clazz.getType());
- Supplier<ClassNaming.Builder> onDemandClassNamingBuilder =
- Suppliers.memoize(
+ LazyBox<ClassNaming.Builder> onDemandClassNamingBuilder =
+ new LazyBox<>(
() ->
classNameMapperBuilder.classNamingBuilder(
DescriptorUtils.descriptorToJavaType(renamedDescriptor.toString()),
@@ -516,14 +514,14 @@
String sourceFile = originalSourceFile.toString();
if (!RetraceUtils.hasPredictableSourceFileName(clazz.toSourceString(), sourceFile)) {
onDemandClassNamingBuilder
- .get()
+ .computeIfAbsent()
.addMappingInformation(FileNameInformation.build(sourceFile), Unreachable::raise);
}
}
if (isSyntheticClass) {
onDemandClassNamingBuilder
- .get()
+ .computeIfAbsent()
.addMappingInformation(
CompilerSynthesizedMappingInformation.builder().build(), Unreachable::raise);
}
@@ -621,13 +619,13 @@
}
MemberNaming memberNaming = new MemberNaming(originalSignature, obfuscatedName);
- onDemandClassNamingBuilder.get().addMemberEntry(memberNaming);
+ onDemandClassNamingBuilder.computeIfAbsent().addMemberEntry(memberNaming);
// Add simple "a() -> b" mapping if we won't have any other with concrete line numbers
if (mappedPositions.isEmpty()) {
MappedRange range =
onDemandClassNamingBuilder
- .get()
+ .computeIfAbsent()
.addMappedRange(null, originalSignature, null, obfuscatedName);
methodMappingInfo.forEach(
info -> range.addMappingInformation(info, Unreachable::raise));
@@ -702,7 +700,7 @@
obfuscatedRange =
new Range(firstPosition.obfuscatedLine, lastPosition.obfuscatedLine);
}
- ClassNaming.Builder classNamingBuilder = onDemandClassNamingBuilder.get();
+ ClassNaming.Builder classNamingBuilder = onDemandClassNamingBuilder.computeIfAbsent();
MappedRange lastMappedRange =
getMappedRangesForPosition(
appView.options().dexItemFactory(),
@@ -895,11 +893,11 @@
private static void addClassToClassNaming(
DexType originalType,
DexString renamedClassName,
- Supplier<Builder> onDemandClassNamingBuilder) {
+ LazyBox<Builder> onDemandClassNamingBuilder) {
// We do know we need to create a ClassNaming.Builder if the class itself had been renamed.
if (originalType.descriptor != renamedClassName) {
// Not using return value, it's registered in classNameMapperBuilder
- onDemandClassNamingBuilder.get();
+ onDemandClassNamingBuilder.computeIfAbsent();
}
}
@@ -908,7 +906,7 @@
NamingLens namingLens,
DexProgramClass clazz,
DexType originalType,
- Supplier<Builder> onDemandClassNamingBuilder) {
+ LazyBox<Builder> onDemandClassNamingBuilder) {
clazz.forEachField(
dexEncodedField -> {
DexField dexField = dexEncodedField.getReference();
@@ -918,7 +916,7 @@
FieldSignature originalSignature =
FieldSignature.fromDexField(originalField, originalField.holder != originalType);
MemberNaming memberNaming = new MemberNaming(originalSignature, renamedName.toString());
- onDemandClassNamingBuilder.get().addMemberEntry(memberNaming);
+ onDemandClassNamingBuilder.computeIfAbsent().addMemberEntry(memberNaming);
}
});
}
diff --git a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
index 19f89d8..c33d020 100644
--- a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
+++ b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.errors.Unreachable;
+import java.util.function.Function;
/** Two value continuation value to indicate the continuation of a loop/traversal. */
/* This class is used for building up api class member traversals. */
@@ -25,14 +26,29 @@
return null;
}
+ public <TBx, TCx> TraversalContinuation<TBx, TCx> map(
+ Function<TB, TBx> mapBreak, Function<TC, TCx> mapContinue) {
+ if (isBreak()) {
+ return new Break<>(mapBreak.apply(asBreak().getValue()));
+ } else {
+ assert isContinue();
+ return new Continue<>(mapContinue.apply(asContinue().getValue()));
+ }
+ }
+
public static class Continue<TB, TC> extends TraversalContinuation<TB, TC> {
- private static final TraversalContinuation<?, ?> CONTINUE_NO_VALUE =
+ private static final TraversalContinuation.Continue<?, ?> CONTINUE_NO_VALUE =
new Continue<Object, Object>(null) {
@Override
public Object getValue() {
return new Unreachable(
"Invalid attempt at getting a value from a no-value continue state.");
}
+
+ @Override
+ public Object getValueOrDefault(Object defaultValue) {
+ return defaultValue;
+ }
};
private final TC value;
@@ -45,6 +61,10 @@
return value;
}
+ public TC getValueOrDefault(TC defaultValue) {
+ return value;
+ }
+
@Override
public boolean isContinue() {
return true;
@@ -57,13 +77,18 @@
}
public static class Break<TB, TC> extends TraversalContinuation<TB, TC> {
- private static final TraversalContinuation<?, ?> BREAK_NO_VALUE =
+ private static final TraversalContinuation.Break<?, ?> BREAK_NO_VALUE =
new Break<Object, Object>(null) {
@Override
public Object getValue() {
return new Unreachable(
"Invalid attempt at getting a value from a no-value break state.");
}
+
+ @Override
+ public Object getValueOrDefault(Object defaultValue) {
+ return defaultValue;
+ }
};
private final TB value;
@@ -76,6 +101,10 @@
return value;
}
+ public TB getValueOrDefault(TB defaultValue) {
+ return value;
+ }
+
@Override
public boolean isBreak() {
return true;
@@ -87,29 +116,34 @@
}
}
- public static TraversalContinuation<?, ?> breakIf(boolean condition) {
+ public static <TB, TC> TraversalContinuation<TB, TC> breakIf(boolean condition) {
return continueIf(!condition);
}
- public static TraversalContinuation<?, ?> continueIf(boolean condition) {
+ public static <TB, TC> TraversalContinuation<TB, TC> continueIf(boolean condition) {
return condition ? doContinue() : doBreak();
}
- @SuppressWarnings("unchecked")
- public static <TB, TC> TraversalContinuation<TB, TC> doContinue() {
- return (TraversalContinuation<TB, TC>) Continue.CONTINUE_NO_VALUE;
+ public TraversalContinuation<TB, TC> ifContinueThen(
+ Function<TraversalContinuation.Continue<TB, TC>, TraversalContinuation<TB, TC>> fn) {
+ return isContinue() ? fn.apply(asContinue()) : this;
}
- public static <TB, TC> TraversalContinuation<TB, TC> doContinue(TC value) {
+ @SuppressWarnings("unchecked")
+ public static <TB, TC> TraversalContinuation.Continue<TB, TC> doContinue() {
+ return (TraversalContinuation.Continue<TB, TC>) Continue.CONTINUE_NO_VALUE;
+ }
+
+ public static <TB, TC> TraversalContinuation.Continue<TB, TC> doContinue(TC value) {
return new Continue<>(value);
}
@SuppressWarnings("unchecked")
- public static <TB, TC> TraversalContinuation<TB, TC> doBreak() {
- return (TraversalContinuation<TB, TC>) Break.BREAK_NO_VALUE;
+ public static <TB, TC> TraversalContinuation.Break<TB, TC> doBreak() {
+ return (TraversalContinuation.Break<TB, TC>) Break.BREAK_NO_VALUE;
}
- public static <TB, TC> TraversalContinuation<TB, TC> doBreak(TB value) {
+ public static <TB, TC> TraversalContinuation.Break<TB, TC> doBreak(TB value) {
return new Break<>(value);
}
diff --git a/src/main/java/com/android/tools/r8/utils/TraversalUtils.java b/src/main/java/com/android/tools/r8/utils/TraversalUtils.java
new file mode 100644
index 0000000..25e1be0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/TraversalUtils.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils;
+
+import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument;
+
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class TraversalUtils {
+
+ public static <BT, CT> BT getFirst(
+ Function<Function<BT, TraversalContinuation<BT, CT>>, TraversalContinuation<BT, CT>>
+ traversal) {
+ return traversal.apply(TraversalContinuation::doBreak).asBreak().getValue();
+ }
+
+ public static <BT, CT> boolean isSingleton(
+ Consumer<Function<CT, TraversalContinuation<BT, CT>>> traversal) {
+ return isSizeExactly(traversal, 1);
+ }
+
+ public static <BT, CT> boolean isSizeExactly(
+ Consumer<Function<CT, TraversalContinuation<BT, CT>>> traversal, int value) {
+ IntBox counter = new IntBox();
+ traversal.accept(
+ ignoreArgument(() -> TraversalContinuation.breakIf(counter.incrementAndGet() > value)));
+ return counter.get() == value;
+ }
+
+ public static <BT, CT> boolean isSizeGreaterThan(
+ Consumer<Function<CT, TraversalContinuation<BT, CT>>> traversal, int value) {
+ IntBox counter = new IntBox();
+ traversal.accept(
+ ignoreArgument(() -> TraversalContinuation.breakIf(counter.incrementAndGet() > value)));
+ return counter.get() > value;
+ }
+
+ public static <S, BT, CT> TraversalContinuation<BT, CT> traverseIterable(
+ Iterable<S> iterable,
+ BiFunction<? super S, ? super CT, TraversalContinuation<BT, CT>> fn,
+ CT initialValue) {
+ TraversalContinuation<BT, CT> traversalContinuation =
+ TraversalContinuation.doContinue(initialValue);
+ for (S element : iterable) {
+ traversalContinuation =
+ fn.apply(element, traversalContinuation.asContinue().getValueOrDefault(null));
+ if (traversalContinuation.isBreak()) {
+ break;
+ }
+ }
+ return traversalContinuation;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java b/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java
index 7dc7b3e..32ab490 100644
--- a/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java
+++ b/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java
@@ -111,7 +111,7 @@
SingleResolutionResult<?> resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(implementer, interfaceMethod)
+ .resolveMethodOnClassLegacy(implementer, interfaceMethod)
.asSingleResolution();
if (resolutionResult == null || !resolutionResult.getResolvedHolder().isProgramClass()) {
continue;
diff --git a/src/main/keep.txt b/src/main/keep.txt
index e376924..deb8e6d 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -12,7 +12,6 @@
-keep public class com.android.tools.r8.D8 { public static void main(java.lang.String[]); }
-keep public class com.android.tools.r8.R8 { public static void main(java.lang.String[]); }
-keep public class com.android.tools.r8.ExtractMarker { public static void main(java.lang.String[]); }
--keep public class com.android.tools.r8.dexsplitter.DexSplitter { public static void main(java.lang.String[]); }
-keep public class com.android.tools.r8.Version { public static final java.lang.String LABEL; }
-keep public class com.android.tools.r8.Version { public static java.lang.String getVersionString(); }
diff --git a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
index 318b3c2..8ba7823 100644
--- a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
+++ b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
@@ -111,7 +111,7 @@
testBuilder
.run(parameters.getRuntime(), "MySubscriber")
.applyIf(
- parameters.asDexRuntime().getVersion().isOlderThan(DexVm.Version.V13_MASTER),
+ parameters.asDexRuntime().getVersion().isOlderThan(DexVm.Version.V13_0_0),
b ->
b.assertFailureWithErrorThatMatches(
anyOf(
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index cf27d33..1ec4d18 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -123,13 +123,10 @@
return self();
}
- // TODO(b/183125319): Make this the default as part of API support in D8.
public D8TestBuilder internalEnableMappingOutput() {
assert proguardMapOutputBuilder == null;
proguardMapOutputBuilder = new StringBuilder();
- // TODO(b/183125319): Use the API once supported in D8.
- addOptionsModification(
- o -> o.proguardMapConsumer = (s, h) -> proguardMapOutputBuilder.append(s));
+ getBuilder().setProguardMapConsumer((s, h) -> proguardMapOutputBuilder.append(s));
return self();
}
}
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index c860721..10c5358 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -102,7 +102,7 @@
DexVm.Version.V9_0_0,
DexVm.Version.V10_0_0,
DexVm.Version.V12_0_0,
- DexVm.Version.V13_MASTER);
+ DexVm.Version.V13_0_0);
private static final String JUNIT_TEST_RUNNER = "org.junit.runner.JUnitCore";
private static final String JUNIT_JAR = "third_party/junit/junit-4.13-beta-2.jar";
@@ -186,13 +186,13 @@
.put(
"098-ddmc",
TestCondition.match(
- TestCondition.runtimes(DexVm.Version.V12_0_0, DexVm.Version.V13_MASTER)))
+ TestCondition.runtimes(DexVm.Version.V12_0_0, DexVm.Version.V13_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, DexVm.Version.V13_MASTER)))
+ TestCondition.runtimes(DexVm.Version.V12_0_0, DexVm.Version.V13_0_0)))
.build();
// Tests that are flaky with the Art version we currently use.
@@ -499,7 +499,7 @@
ImmutableMap.Builder<DexVm.Version, List<String>> builder = ImmutableMap.builder();
builder
.put(
- DexVm.Version.V13_MASTER,
+ DexVm.Version.V13_0_0,
ImmutableList.of("454-get-vreg", "457-regs", "543-env-long-ref", "518-null-array-get"))
.put(
DexVm.Version.V12_0_0,
@@ -848,7 +848,7 @@
DexVm.Version.V5_1_1,
DexVm.Version.V6_0_1,
DexVm.Version.V7_0_0,
- DexVm.Version.V13_MASTER)),
+ DexVm.Version.V13_0_0)),
TestCondition.match(
TestCondition.compilers(
CompilerUnderTest.R8,
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index 8478b17..a7759e3 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -90,7 +90,7 @@
// TODO(120402963) Triage.
ImmutableList.of("invokecustom-with-shrinking", "invokecustom2-with-shrinking"))
.put(
- Version.V13_MASTER,
+ Version.V13_0_0,
// TODO(120402963) Triage.
ImmutableList.of("invokecustom-with-shrinking", "invokecustom2-with-shrinking"))
.put(Version.DEFAULT, ImmutableList.of())
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 1d6cb9a..e1064b0 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -15,7 +15,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -35,8 +34,79 @@
@Rule
public ExpectedException thrown = ExpectedException.none();
+ @Parameters(name = "{0}: {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(), tests.keySet());
+ }
+
private static final String SMALI_DIR = ToolHelper.SMALI_BUILD_DIR;
+ private static Map<String, String> tests;
+
+ static {
+ ImmutableMap.Builder<String, String> testsBuilder = ImmutableMap.builder();
+ testsBuilder
+ .put(
+ "arithmetic",
+ StringUtils.lines(
+ "-1", "3", "2", "3", "3.0", "1", "0", "-131580", "-131580", "2", "4", "-2"))
+ .put(
+ "controlflow",
+ StringUtils.lines("2", "1", "2", "1", "2", "1", "2", "1", "2", "1", "2", "1", "2"))
+ .put("fibonacci", StringUtils.lines("55", "55", "55", "55"))
+ .put("fill-array-data", "[1, 2, 3][4, 5, 6]")
+ .put("filled-new-array", "[1, 2, 3][4, 5, 6][1, 2, 3, 4, 5, 6][6, 5, 4, 3, 2, 1]")
+ .put("packed-switch", "12345")
+ .put("sparse-switch", "12345")
+ .put("unreachable-code-1", "777")
+ .put(
+ "multiple-returns",
+ StringUtils.lines("TFtf", "1", "4611686018427387904", "true", "false"))
+ .put("try-catch", "")
+ .put("phi-removal-regression", StringUtils.lines("returnBoolean"))
+ .put(
+ "overlapping-long-registers",
+ StringUtils.lines("-9151314442816847872", "-9151314442816319488"))
+ .put(
+ "type-confusion-regression",
+ StringUtils.lines("java.lang.RuntimeException: Test.<init>()"))
+ .put(
+ "type-confusion-regression2",
+ StringUtils.lines("java.lang.NullPointerException: Attempt to read from null array"))
+ .put(
+ "type-confusion-regression3",
+ StringUtils.lines(
+ "java.lang.NullPointerException: Attempt to read from field 'byte[] Test.a'"
+ + " on a null object reference"))
+ .put("type-confusion-regression4", "")
+ .put(
+ "type-confusion-regression5", StringUtils.lines("java.lang.RuntimeException: getId()I"))
+ .put("chain-of-loops", StringUtils.lines("java.lang.RuntimeException: f(II)"))
+ .put("new-instance-and-init", StringUtils.lines("Test(0)", "Test(0)", "Test(0)"))
+ .put(
+ "bad-codegen",
+ StringUtils.lines(
+ "java.lang.NullPointerException: Attempt to read from field "
+ + "'Test Test.a' on a null object reference"))
+ .put(
+ "merge-blocks-regression",
+ StringUtils.lines(
+ "java.lang.NullPointerException: Attempt to invoke virtual"
+ + " method 'Test Test.bW_()' on a null object reference"))
+ .put("self-is-catch-block", StringUtils.lines("100", "-1"))
+ .put("infinite-loop", "")
+ .put(
+ "regression/33336471",
+ StringUtils.lines(
+ "START", "0", "2", "LOOP", "1", "2", "LOOP", "2", "2", "DONE", "START", "0", "2",
+ "LOOP", "1", "2", "LOOP", "2", "2", "DONE"))
+ .put("regression/33846227", "")
+ .put("illegal-invokes", StringUtils.lines("ICCE", "ICCE"))
+ .build();
+ tests = testsBuilder.build();
+ }
+
private static Map<String, Set<String>> missingClasses =
ImmutableMap.of(
"try-catch", ImmutableSet.of("test.X"),
@@ -44,60 +114,63 @@
"bad-codegen", ImmutableSet.of("java.util.LTest"));
// Tests where the original smali code fails on Art, but runs after R8 processing.
- private static Map<DexVm.Version, List<String>> originalFailingOnArtVersions = ImmutableMap.of(
- Version.V5_1_1, ImmutableList.of(
- // Smali code contains an empty switch payload.
- "sparse-switch",
- "regression/33846227"
- ),
- Version.V4_4_4, ImmutableList.of(
- // Smali code contains an empty switch payload.
- "sparse-switch",
- "regression/33846227"
- ),
- Version.V4_0_4, ImmutableList.of(
- // Smali code contains an empty switch payload.
- "sparse-switch",
- "regression/33846227"
- )
- );
+ private static final Map<DexVm.Version, List<String>> originalFailingOnArtVersions =
+ ImmutableMap.of(
+ Version.V5_1_1,
+ ImmutableList.of(
+ // Smali code contains an empty switch payload.
+ "sparse-switch", "regression/33846227"),
+ Version.V4_4_4,
+ ImmutableList.of(
+ // Smali code contains an empty switch payload.
+ "sparse-switch", "regression/33846227"),
+ Version.V4_0_4,
+ ImmutableList.of(
+ // Smali code contains an empty switch payload.
+ "sparse-switch", "regression/33846227"));
// Tests where the output has a different output than the original on certain VMs.
- private static Map<DexVm.Version, Map<String, String>> customProcessedOutputExpectation =
+ private static final Map<DexVm.Version, Map<String, String>> customProcessedOutputExpectation =
ImmutableMap.of(
- Version.V4_4_4, ImmutableMap.of(
- "bad-codegen", "java.lang.NullPointerException\n",
- "type-confusion-regression2", "java.lang.NullPointerException\n",
- "type-confusion-regression3", "java.lang.NullPointerException\n",
- "merge-blocks-regression", "java.lang.NullPointerException\n"
- ),
- Version.V4_0_4, ImmutableMap.of(
- "bad-codegen", "java.lang.NullPointerException\n",
- "type-confusion-regression2", "java.lang.NullPointerException\n",
- "type-confusion-regression3", "java.lang.NullPointerException\n",
- "merge-blocks-regression", "java.lang.NullPointerException\n"
- )
- );
+ Version.V4_4_4,
+ ImmutableMap.of(
+ "bad-codegen", "java.lang.NullPointerException\n",
+ "type-confusion-regression2", "java.lang.NullPointerException\n",
+ "type-confusion-regression3", "java.lang.NullPointerException\n",
+ "merge-blocks-regression", "java.lang.NullPointerException\n"),
+ Version.V4_0_4,
+ ImmutableMap.of(
+ "bad-codegen", "java.lang.NullPointerException\n",
+ "type-confusion-regression2", "java.lang.NullPointerException\n",
+ "type-confusion-regression3", "java.lang.NullPointerException\n",
+ "merge-blocks-regression", "java.lang.NullPointerException\n"),
+ Version.V13_0_0,
+ ImmutableMap.of(
+ "bad-codegen",
+ StringUtils.lines(
+ "java.lang.NullPointerException: Attempt to read from field 'Test Test.a'"
+ + " on a null object reference in method 'Test TestObject.a(Test,"
+ + " Test, Test, Test, boolean)'"),
+ "type-confusion-regression3",
+ StringUtils.lines(
+ "java.lang.NullPointerException: Attempt to read from field 'byte[]"
+ + " Test.a' on a null object reference in method 'int"
+ + " TestObject.a(Test, Test)'")));
// Tests where the input fails with a verification error on Dalvik instead of the
// expected runtime exception.
- private static Map<DexVm.Version, List<String>> dalvikVerificationError = ImmutableMap.of(
- Version.V4_4_4, ImmutableList.of(
- // The invokes are in fact invalid, but the test expects the current Art behavior
- // of throwing an IncompatibleClassChange exception. Dalvik fails to verify.
- "illegal-invokes"
- ),
- Version.V4_0_4, ImmutableList.of(
- // The invokes are in fact invalid, but the test expects the current Art behavior
- // of throwing an IncompatibleClassChange exception. Dalvik fails to verify.
- "illegal-invokes"
- )
- );
-
- // Tests where the original smali code runs on Art, but fails after R8 processing
- private static Map<String, List<String>> failingOnArtVersions = ImmutableMap.of(
- // This list is currently empty!
- );
+ private static final Map<DexVm.Version, List<String>> dalvikVerificationErrors =
+ ImmutableMap.of(
+ Version.V4_4_4,
+ ImmutableList.of(
+ // The invokes are in fact invalid, but the test expects the current Art behavior
+ // of throwing an IncompatibleClassChange exception. Dalvik fails to verify.
+ "illegal-invokes"),
+ Version.V4_0_4,
+ ImmutableList.of(
+ // The invokes are in fact invalid, but the test expects the current Art behavior
+ // of throwing an IncompatibleClassChange exception. Dalvik fails to verify.
+ "illegal-invokes"));
private Set<String> failingOnX8 = ImmutableSet.of(
// Contains use of register as both an int and a float.
@@ -110,59 +183,23 @@
@Rule
public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
- @Parameters(name = "{0}")
- public static Collection<String[]> data() {
- return Arrays.asList(new String[][]{
- {"arithmetic",
- StringUtils.lines("-1", "3", "2", "3", "3.0", "1", "0", "-131580", "-131580", "2", "4",
- "-2")},
- {"controlflow",
- StringUtils.lines("2", "1", "2", "1", "2", "1", "2", "1", "2", "1", "2", "1", "2")},
- {"fibonacci", StringUtils.lines("55", "55", "55", "55")},
- {"fill-array-data", "[1, 2, 3][4, 5, 6]"},
- {"filled-new-array", "[1, 2, 3][4, 5, 6][1, 2, 3, 4, 5, 6][6, 5, 4, 3, 2, 1]"},
- {"packed-switch", "12345"},
- {"sparse-switch", "12345"},
- {"unreachable-code-1", "777"},
- {"multiple-returns",
- StringUtils.lines("TFtf", "1", "4611686018427387904", "true", "false")},
- {"try-catch", ""},
- {"phi-removal-regression", StringUtils.lines("returnBoolean")},
- {"overlapping-long-registers",
- StringUtils.lines("-9151314442816847872", "-9151314442816319488")},
- {"type-confusion-regression",
- StringUtils.lines("java.lang.RuntimeException: Test.<init>()")},
- {"type-confusion-regression2",
- StringUtils.lines("java.lang.NullPointerException: Attempt to read from null array")},
- {"type-confusion-regression3",
- StringUtils.lines(
- "java.lang.NullPointerException: Attempt to read from field 'byte[] Test.a'" +
- " on a null object reference")},
- {"type-confusion-regression4", ""},
- {"type-confusion-regression5", StringUtils.lines("java.lang.RuntimeException: getId()I")},
- {"chain-of-loops", StringUtils.lines("java.lang.RuntimeException: f(II)")},
- {"new-instance-and-init", StringUtils.lines("Test(0)", "Test(0)", "Test(0)")},
- {"bad-codegen",
- StringUtils.lines("java.lang.NullPointerException: Attempt to read from field " +
- "'Test Test.a' on a null object reference")},
- {"merge-blocks-regression",
- StringUtils.lines("java.lang.NullPointerException: Attempt to invoke virtual"
- + " method 'Test Test.bW_()' on a null object reference")},
- {"self-is-catch-block", StringUtils.lines("100", "-1")},
- {"infinite-loop", ""},
- {"regression/33336471",
- StringUtils.lines("START", "0", "2", "LOOP", "1", "2", "LOOP", "2", "2", "DONE",
- "START", "0", "2", "LOOP", "1", "2", "LOOP", "2", "2", "DONE")},
- {"regression/33846227", ""},
- {"illegal-invokes", StringUtils.lines("ICCE", "ICCE")},
- });
- }
+ private final TestParameters parameters;
+ private final String directoryName;
+ private final String dexFileName;
+ private final String expectedOutput;
- private String directoryName;
- private String dexFileName;
- private String expectedOutput;
-
- public R8RunSmaliTestsTest(String name, String expectedOutput) {
+ public R8RunSmaliTestsTest(TestParameters parameters, String name) {
+ this.parameters = parameters;
+ String expectedOutput = tests.get(name);
+ if (customProcessedOutputExpectation.containsKey(parameters.asDexRuntime().getVersion())
+ && customProcessedOutputExpectation
+ .get(parameters.asDexRuntime().getVersion())
+ .containsKey(name)) {
+ // If the original and the processed code have different expected output, only run
+ // the code produced by R8.
+ expectedOutput =
+ customProcessedOutputExpectation.get(parameters.asDexRuntime().getVersion()).get(name);
+ }
this.directoryName = name;
this.dexFileName = name.substring(name.lastIndexOf('/') + 1) + ".dex";
this.expectedOutput = expectedOutput;
@@ -171,56 +208,40 @@
@Test
public void SmaliTest() throws Exception {
Path originalDexFile = Paths.get(SMALI_DIR, directoryName, dexFileName);
- Path outputPath = temp.getRoot().toPath().resolve("classes.dex");
+ // Path outputPath = temp.getRoot().toPath().resolve("classes.dex");
if (failingOnX8.contains(directoryName)) {
thrown.expect(CompilationFailedException.class);
}
- testForR8(Backend.DEX)
+ Version version = parameters.asDexRuntime().getVersion();
+ boolean dalvikVerificationError =
+ dalvikVerificationErrors.containsKey(version)
+ && dalvikVerificationErrors.get(version).contains(directoryName);
+ boolean originalFailing =
+ (originalFailingOnArtVersions.containsKey(version)
+ && originalFailingOnArtVersions.get(version).contains(directoryName));
+ testForR8(parameters.getBackend())
.addKeepAllClassesRule()
.addProgramDexFileData(Files.readAllBytes(originalDexFile))
.addDontWarn(missingClasses.getOrDefault(directoryName, Collections.emptySet()))
+ .setMinApi(parameters.getApiLevel())
.compile()
- .writeToZip(outputPath);
+ .run(parameters.getRuntime(), "Test")
+ .applyIf(
+ dalvikVerificationError,
+ r -> r.assertFailureWithErrorThatThrows(VerifyError.class),
+ r -> r.assertSuccessWithOutput(expectedOutput));
- if (!ToolHelper.artSupported()) {
- return;
+ // Also run the original DEX if possible.
+ if (!dalvikVerificationError && !originalFailing) {
+ String originalOutput =
+ ToolHelper.runArtNoVerificationErrors(
+ ImmutableList.of(originalDexFile.toString()),
+ "Test",
+ null,
+ parameters.getRuntime().asDex().getVm());
+ assertEquals(expectedOutput, originalOutput);
}
-
- String mainClass = "Test";
- String generated = outputPath.toString();
- String output = "";
-
- DexVm.Version dexVmVersion = ToolHelper.getDexVm().getVersion();
- if (dalvikVerificationError.containsKey(dexVmVersion)
- && dalvikVerificationError.get(dexVmVersion).contains(directoryName)) {
- try {
- ToolHelper.runArtNoVerificationErrors(generated, mainClass);
- } catch (AssertionError e) {
- assert e.toString().contains("VerifyError");
- }
- return;
- } else if (originalFailingOnArtVersions.containsKey(dexVmVersion)
- && originalFailingOnArtVersions.get(dexVmVersion).contains(directoryName)) {
- // If the original smali code fails on the target VM, only run the code produced by R8.
- output = ToolHelper.runArtNoVerificationErrors(generated, mainClass);
- } else if (customProcessedOutputExpectation.containsKey(dexVmVersion)
- && customProcessedOutputExpectation.get(dexVmVersion).containsKey(directoryName)) {
- // If the original and the processed code have different expected output, only run
- // the code produced by R8.
- expectedOutput =
- customProcessedOutputExpectation.get(dexVmVersion).get(directoryName);
- output = ToolHelper.runArtNoVerificationErrors(generated, mainClass);
- } else {
- if (failingOnArtVersions.containsKey(dexVmVersion)
- && failingOnArtVersions.get(dexVmVersion).contains(directoryName)) {
- thrown.expect(Throwable.class);
- }
- output =
- ToolHelper
- .checkArtOutputIdentical(originalDexFile.toString(), generated, mainClass, null);
- }
- assertEquals(expectedOutput, output);
}
}
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index e6cd425..7fe1ae0 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -310,7 +310,7 @@
// TODO(b/120402963): Triage.
"invokecustom", "invokecustom2"))
.put(
- Version.V13_MASTER,
+ Version.V13_0_0,
ImmutableList.of(
// TODO(b/120402963): Triage.
"invokecustom", "invokecustom2"))
diff --git a/src/test/java/com/android/tools/r8/SanityCheck.java b/src/test/java/com/android/tools/r8/SanityCheck.java
index df1486c..c461475 100644
--- a/src/test/java/com/android/tools/r8/SanityCheck.java
+++ b/src/test/java/com/android/tools/r8/SanityCheck.java
@@ -117,7 +117,6 @@
@Test
public void testJarsContent() throws Exception {
- checkJarContent(ToolHelper.D8_JAR);
checkJarContent(ToolHelper.R8_JAR);
}
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 21ca89e..097e4bc 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -785,7 +785,7 @@
return computeAppViewWithClassHierarchy(app, keepConfig, null);
}
- private static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy(
+ protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy(
AndroidApp app,
Function<DexItemFactory, ProguardConfiguration> keepConfig,
Consumer<InternalOptions> optionsConsumer)
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 719dbd8..48f9fc5 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -331,6 +331,15 @@
}
}
+ public CR addBootClasspathFiles(Path... files) {
+ return addBootClasspathFiles(Arrays.asList(files));
+ }
+
+ public CR addBootClasspathFiles(Collection<Path> files) {
+ additionalBootClasspath.addAll(files);
+ return self();
+ }
+
public CR addDesugaredCoreLibraryRunClassPath(
Function<AndroidApiLevel, Path> classPathSupplier, AndroidApiLevel minAPILevel) {
addRunClasspathFiles(classPathSupplier.apply(minAPILevel));
diff --git a/src/test/java/com/android/tools/r8/TestCondition.java b/src/test/java/com/android/tools/r8/TestCondition.java
index cd0a1e7..b1a6207 100644
--- a/src/test/java/com/android/tools/r8/TestCondition.java
+++ b/src/test/java/com/android/tools/r8/TestCondition.java
@@ -53,7 +53,7 @@
return ART_V10_0_0;
case V12_0_0:
return ART_V12_0_0;
- case V13_MASTER:
+ case V13_0_0:
return ART_V13_0_0;
case DEFAULT:
return ART_DEFAULT;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 7bcdfb6..f219969 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -161,7 +161,6 @@
public static final long BOT_MAX_HEAP_SIZE = 7908360192L;
- public static final Path D8_JAR = Paths.get(LIBS_DIR, "d8.jar");
public static final Path R8_JAR = Paths.get(LIBS_DIR, "r8.jar");
public static final Path R8_WITH_DEPS_JAR = Paths.get(LIBS_DIR, "r8_with_deps.jar");
public static final Path R8_WITHOUT_DEPS_JAR =
@@ -204,12 +203,16 @@
return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs.json");
}
+ public static Path getDesugarLibJsonForTestingWithPath() {
+ return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_path.json");
+ }
+
public static Path getCHMOnlyDesugarLibJsonForTesting() {
return Paths.get(getDesugarLibraryJsonDir(), "chm_only_desugar_jdk_libs.json");
}
public static Path getDesugarLibJsonForTestingAlternative3() {
- return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_alternative_3.json");
+ return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_path_alternative_3.json");
}
public static boolean isLocalDevelopment() {
@@ -271,8 +274,8 @@
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),
- ART_13_0_0_TARGET(Version.V13_MASTER, Kind.TARGET),
- ART_13_0_0_HOST(Version.V13_MASTER, Kind.HOST);
+ ART_13_0_0_TARGET(Version.V13_0_0, Kind.TARGET),
+ ART_13_0_0_HOST(Version.V13_0_0, Kind.HOST);
private static final ImmutableMap<String, DexVm> SHORT_NAME_MAP =
Arrays.stream(DexVm.values()).collect(ImmutableMap.toImmutableMap(
@@ -290,7 +293,7 @@
V9_0_0("9.0.0"),
V10_0_0("10.0.0"),
V12_0_0("12.0.0"),
- V13_MASTER("13.0.0");
+ V13_0_0("13.0.0");
/** This should generally be the latest DEX VM fully supported. */
// TODO(b/204855476): Rename to DEFAULT alias once the checked in VM is removed.
@@ -352,7 +355,7 @@
}
public static Version last() {
- return V13_MASTER;
+ return V13_0_0;
}
static {
@@ -623,7 +626,7 @@
private static final Map<DexVm, String> ART_DIRS =
ImmutableMap.<DexVm, String>builder()
.put(DexVm.ART_DEFAULT, "art")
- .put(DexVm.ART_13_0_0_HOST, "host/art-13-master")
+ .put(DexVm.ART_13_0_0_HOST, "host/art-13-dev")
.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")
@@ -673,14 +676,21 @@
"core-oj-hostdex.jar",
"apache-xml-hostdex.jar");
+ private static final List<String> NEWER_ART_BOOT_LIBS =
+ ImmutableList.of(
+ "core-libart-hostdex.jar",
+ "core-oj-hostdex.jar",
+ "core-icu4j-hostdex.jar",
+ "apache-xml-hostdex.jar");
+
private static final Map<DexVm, List<String>> BOOT_LIBS;
static {
ImmutableMap.Builder<DexVm, List<String>> builder = ImmutableMap.builder();
builder
.put(DexVm.ART_DEFAULT, ART_BOOT_LIBS)
- .put(DexVm.ART_13_0_0_HOST, ART_BOOT_LIBS)
- .put(DexVm.ART_12_0_0_HOST, ART_BOOT_LIBS)
+ .put(DexVm.ART_13_0_0_HOST, NEWER_ART_BOOT_LIBS)
+ .put(DexVm.ART_12_0_0_HOST, NEWER_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)
@@ -1027,7 +1037,7 @@
public static AndroidApiLevel getMinApiLevelForDexVm(DexVm dexVm) {
switch (dexVm.version) {
- case V13_MASTER:
+ case V13_0_0:
return AndroidApiLevel.T;
case V12_0_0:
return AndroidApiLevel.S;
@@ -1996,7 +2006,7 @@
"b/144975341",
vm.version == DexVm.Version.V10_0_0
|| vm.version == DexVm.Version.V12_0_0
- || vm.version == DexVm.Version.V13_MASTER);
+ || vm.version == DexVm.Version.V13_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/ApiModelMockClassInstanceInitTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
index 784fce6..61a9e78 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
@@ -9,7 +9,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -58,10 +57,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -74,10 +70,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
// TODO(b/213552119): Remove when enabled by default.
@@ -92,10 +85,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
index 8651a23..ec4a09e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -16,7 +15,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Test;
@@ -54,10 +52,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -70,10 +65,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
// TODO(b/213552119): Remove when enabled by default.
@@ -88,10 +80,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
index 1397da7..b999875 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -17,7 +16,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -62,10 +60,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -78,10 +73,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
// TODO(b/213552119): Remove when enabled by default.
@@ -96,10 +88,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index 3d6d30c..78c5fc1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -16,7 +15,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -61,10 +59,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -77,10 +72,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
// TODO(b/213552119): Remove when enabled by default.
@@ -95,10 +87,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index c2a6d4d..d6911db 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -16,7 +15,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -71,10 +69,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -92,10 +87,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
// TODO(b/213552119): Remove when enabled by default.
@@ -115,10 +107,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
index 85429ea..a3183b0 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
@@ -11,7 +11,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.NeverInline;
@@ -21,7 +20,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
@@ -67,10 +65,7 @@
@Test
public void testD8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
String result;
if (parameters.isDexRuntime()
&& parameters.getApiLevel().isGreaterThanOrEqualTo(libraryApiLevel)) {
@@ -90,10 +85,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
index e8d6257..57eaa67 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
@@ -13,7 +13,6 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -23,7 +22,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -77,10 +75,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -93,9 +88,7 @@
@Test
public void testD8Release() throws Exception {
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
@@ -108,9 +101,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
index fb98821..9793b9b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
@@ -10,7 +10,6 @@
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethodWithName;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -20,7 +19,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -90,10 +88,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8(parameters.getBackend())
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -120,10 +115,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8(parameters.getBackend())
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
@@ -138,10 +130,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
index 2411e94..0b2f270 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
@@ -8,7 +8,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -17,7 +16,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.apimodel.ApiModelMockClassTest.TestClass;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -69,10 +67,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8(parameters.getBackend())
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -85,10 +80,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8(parameters.getBackend())
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
@@ -101,10 +93,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
index cf440c9..0fbd97c 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -13,7 +13,6 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -23,7 +22,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -87,10 +85,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8(parameters.getBackend())
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -103,9 +98,7 @@
@Test
public void testD8Release() throws Exception {
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8(parameters.getBackend())
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
@@ -118,10 +111,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
index d63e01b..39b1db2 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -19,7 +18,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.lang.reflect.Method;
@@ -93,10 +91,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -108,10 +103,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
@@ -123,10 +115,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
index 940864c..fdd796b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.apimodel;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -14,7 +13,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import org.junit.Test;
@@ -56,10 +54,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -73,10 +68,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isCfRuntime()
- || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
@@ -90,10 +82,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
index 94ae936..abf4efd 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -16,7 +15,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import org.junit.Test;
@@ -45,9 +43,7 @@
@Test
public void testD8BootClassPath() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
assumeTrue(parameters.isDexRuntime());
- assumeTrue(parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
compileOnD8()
.addBootClasspathClasses(LibraryClass.class)
.run(parameters.getRuntime(), Main.class)
@@ -92,10 +88,7 @@
@Test
public void testD8Debug() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
@@ -109,10 +102,7 @@
@Test
public void testD8Release() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeTrue(parameters.isDexRuntime());
testForD8()
.apply(this::setupTestBuilder)
.compile()
@@ -125,10 +115,6 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
index e4a1a1a..57aaddc 100644
--- a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
@@ -79,7 +79,7 @@
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnInterfaceHolder(method);
+ appView.appInfo().resolveMethodOnInterfaceHolderLegacy(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeL = buildType(L.class, appView.dexItemFactory());
DexType typeA = buildType(A.class, appView.dexItemFactory());
@@ -121,7 +121,7 @@
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnInterfaceHolder(method);
+ appView.appInfo().resolveMethodOnInterfaceHolderLegacy(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeL = buildType(L.class, appView.dexItemFactory());
DexType typeA = buildType(A.class, appView.dexItemFactory());
@@ -162,7 +162,7 @@
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(J.class, J.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnInterfaceHolder(method);
+ appView.appInfo().resolveMethodOnInterfaceHolderLegacy(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeB = buildType(A.class, appView.dexItemFactory());
DexProgramClass classI = appView.definitionForProgramType(typeI);
@@ -200,7 +200,7 @@
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(J.class, A.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnInterfaceHolder(method);
+ appView.appInfo().resolveMethodOnInterfaceHolderLegacy(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeB = buildType(A.class, appView.dexItemFactory());
DexProgramClass classI = appView.definitionForProgramType(typeI);
@@ -240,7 +240,7 @@
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnInterfaceHolder(method);
+ appView.appInfo().resolveMethodOnInterfaceHolderLegacy(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeB = buildType(A.class, appView.dexItemFactory());
DexProgramClass classI = appView.definitionForProgramType(typeI);
diff --git a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
index a5e76eb..f3a22bf 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
@@ -5,11 +5,10 @@
package com.android.tools.r8.debuginfo;
import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForFileNameAndLineNumber;
-import static com.android.tools.r8.utils.InternalOptions.LineNumberOptimization.ON;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.SourceFileEnvironment;
@@ -74,7 +73,6 @@
.addProgramClasses(MAIN)
.setMinApi(parameters.getApiLevel())
.internalEnableMappingOutput()
- // TODO(b/191038746): Enable LineNumberOptimization for release builds for DEX PC Output.
.applyIf(
apiLevelSupportsPcAndSourceFileOutput(),
builder ->
@@ -92,7 +90,6 @@
return true;
}
};
- options.lineNumberOptimization = ON;
}))
.run(parameters.getRuntime(), MAIN)
.inspectFailure(
@@ -150,10 +147,7 @@
List<DexDebugEntry> entries =
new DexDebugEntryBuilder(main.getMethod(), inspector.getFactory()).build();
Set<Integer> lines = entries.stream().map(e -> e.line).collect(Collectors.toSet());
- // Check some of the lines in main are present (not 27 as it may be optimized out).
- assertTrue(lines.contains(22));
- assertTrue(lines.contains(23));
- assertTrue(lines.contains(25));
+ assertFalse(lines.isEmpty());
}
private void checkExpectedStackTrace(StackTrace stackTrace) {
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
index d0db2c9..8eff1c5 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -102,7 +102,7 @@
.setMinApi(AndroidApiLevel.ANDROID_PLATFORM)
.run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
.applyIf(
- parameters.getDexRuntimeVersion().isOlderThan(Version.V13_MASTER),
+ parameters.getDexRuntimeVersion().isOlderThan(Version.V13_0_0),
b ->
b.assertFailureWithErrorThatMatches(
containsString(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index 93ea904..fbfcb18 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -7,16 +7,10 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
-import com.google.common.collect.ImmutableList;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.UncheckedIOException;
@@ -54,28 +48,6 @@
return StringUtils.lines("Hello", "Larry", "Page", "Caught java.io.UncheckedIOException");
}
- DesugaredLibrarySpecification configurationAlternative3(
- InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
- // Parse the current configuration and amend the configuration for BufferedReader.lines. The
- // configuration is the same for both program and library.
- return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingAlternative3()),
- options.dexItemFactory(),
- options.reporter,
- libraryCompilation,
- parameters.getApiLevel().getLevel());
- }
-
- private void configurationForProgramCompilation(InternalOptions options) {
- setDesugaredLibrarySpecificationForTesting(
- options, configurationAlternative3(options, false, parameters));
- }
-
- private void configurationForLibraryCompilation(InternalOptions options) {
- setDesugaredLibrarySpecificationForTesting(
- options, configurationAlternative3(options, true, parameters));
- }
-
@Test
public void testBufferedReaderD8Cf() throws Exception {
Assume.assumeTrue(
@@ -85,7 +57,6 @@
// Use D8 to desugar with Java classfile output.
Path jar =
testForD8(Backend.CF)
- .addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -108,13 +79,7 @@
.disableDesugaring()
.compile()
.addDesugaredCoreLibraryRunClassPath(
- (apiLevel, keepRules, shrink) ->
- buildDesugaredLibrary(
- apiLevel,
- keepRules,
- shrink,
- ImmutableList.of(),
- this::configurationForLibraryCompilation),
+ this::buildDesugaredLibrary,
parameters.getApiLevel(),
desugaredLibraryKeepRules,
shrinkDesugaredLibrary)
@@ -122,8 +87,7 @@
.assertSuccessWithOutput(expectedOutput());
} else {
// Build the desugared library in class file format.
- Path desugaredLib =
- getDesugaredLibraryInCF(parameters, this::configurationForLibraryCompilation);
+ Path desugaredLib = getDesugaredLibraryInCF(parameters, opt -> {});
// Run on the JVM with desugared library on classpath.
testForJvm()
@@ -143,19 +107,12 @@
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForD8()
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
- (apiLevel, keepRules, shrink) ->
- buildDesugaredLibrary(
- apiLevel,
- keepRules,
- shrink,
- ImmutableList.of(),
- this::configurationForLibraryCompilation),
+ this::buildDesugaredLibrary,
parameters.getApiLevel(),
keepRuleConsumer.get(),
shrinkDesugaredLibrary)
@@ -172,7 +129,6 @@
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(parameters.getBackend())
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
@@ -180,13 +136,7 @@
.enableInliningAnnotations()
.compile()
.addDesugaredCoreLibraryRunClassPath(
- (apiLevel, keepRules, shrink) ->
- buildDesugaredLibrary(
- apiLevel,
- keepRules,
- shrink,
- ImmutableList.of(),
- this::configurationForLibraryCompilation),
+ this::buildDesugaredLibrary,
parameters.getApiLevel(),
keepRuleConsumer.get(),
shrinkDesugaredLibrary)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java
index 0874b57..dc9725a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java
@@ -35,6 +35,8 @@
.put("java/lang/DesugarMath", "java/lang/Math")
.put("java/io/DesugarBufferedReader", "java/io/BufferedReader")
.put("java/io/DesugarInputStream", "java/io/InputStream")
+ .put("wrapper/adapter/HybridFileSystemProvider", "java/adapter/HybridFileSystemProvider")
+ .put("wrapper/adapter/HybridFileTypeDetector", "java/adapter/HybridFileTypeDetector")
.build();
public static void main(String[] args) throws Exception {
@@ -47,9 +49,6 @@
return ToolHelper.getDesugarJDKLibsBazelGeneratedFile();
}
Path desugaredLibJDK11Undesugared = Paths.get("build/libs/desugar_jdk_libs_11_undesugared.jar");
- if (Files.exists(desugaredLibJDK11Undesugared)) {
- return desugaredLibJDK11Undesugared;
- }
return generateUndesugaredJar(desugaredLibJDK11Undesugared);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileTypeDetectorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileTypeDetectorTest.java
new file mode 100644
index 0000000..b168992
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileTypeDetectorTest.java
@@ -0,0 +1,173 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
+
+import static com.android.tools.r8.ToolHelper.DexVm.Version.V12_0_0;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.spi.FileTypeDetector;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceLoader;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FileTypeDetectorTest extends DesugaredLibraryTestBase {
+
+ private static final String EXPECTED_RESULT_DEFAULT_PNG_TYPE_DETECTOR =
+ StringUtils.lines("false", "text/plain", "image/png", "null", "image/png");
+ private static final String EXPECTED_RESULT_NO_DEFAULT_PNG_TYPE_DETECTOR =
+ StringUtils.lines("false", "text/plain", "null", "null", "image/png");
+ private final TestParameters parameters;
+ private final boolean shrinkDesugaredLibrary;
+
+ @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ public static List<Object[]> data() {
+ // Skip Android 4.4.4 due to missing libjavacrypto.
+ return buildParameters(
+ BooleanUtils.values(),
+ getTestParameters()
+ .withDexRuntime(Version.V4_0_4)
+ .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+ .withAllApiLevels()
+ .build());
+ }
+
+ public FileTypeDetectorTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.parameters = parameters;
+ }
+
+ private boolean hasDefaultPNGTypeDetector() {
+ return parameters.getDexRuntimeVersion().compareTo(V12_0_0) < 0;
+ }
+
+ private String getExpectedResult() {
+ return hasDefaultPNGTypeDetector()
+ ? EXPECTED_RESULT_DEFAULT_PNG_TYPE_DETECTOR
+ : EXPECTED_RESULT_NO_DEFAULT_PNG_TYPE_DETECTOR;
+ }
+
+ private LibraryDesugaringTestConfiguration pathConfiguration() {
+ return LibraryDesugaringTestConfiguration.builder()
+ .setMinApi(parameters.getApiLevel())
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingWithPath()))
+ .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+ .withKeepRuleConsumer()
+ .build();
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(getClass())
+ .addProgramClasses(GoogleIcon.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .withArt6Plus64BitsLib()
+ .withArtFrameworks()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(getExpectedResult());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForR8(Backend.DEX)
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(getClass())
+ .addProgramClasses(GoogleIcon.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(TestClass.class)
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .withArt6Plus64BitsLib()
+ .withArtFrameworks()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(getExpectedResult());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) throws Throwable {
+ // FileTypeDetector usage through ServiceLoader.
+ ServiceLoader<FileTypeDetector> serviceLoader = ServiceLoader.load(FileTypeDetector.class);
+ Iterator<FileTypeDetector> iterator = serviceLoader.iterator();
+ System.out.println(iterator.hasNext());
+ while (iterator.hasNext()) {
+ FileTypeDetector fileTypeDetector = iterator.next();
+ System.out.println((fileTypeDetector == null));
+ }
+
+ Path emptyText = Files.createTempFile("example", ".txt");
+ Path png = getGoogleIconPng();
+
+ // FileTypeDetector usage through Files.
+ System.out.println(Files.probeContentType(emptyText));
+ System.out.println(Files.probeContentType(png));
+
+ // Custom file type detector usage.
+ FileTypeDetector fileTypeDetector = new PngFileTypeDetector();
+ System.out.println(fileTypeDetector.probeContentType(emptyText));
+ System.out.println(fileTypeDetector.probeContentType(png));
+ }
+
+ private static Path getGoogleIconPng() throws IOException {
+ Path picture = Files.createTempFile("art", ".png");
+ Files.write(picture, GoogleIcon.GOOGLE_ICON_PNG);
+ return picture;
+ }
+ }
+
+ public static class PngFileTypeDetector extends FileTypeDetector {
+
+ private static final byte[] PNG_HEADER = {
+ (byte) 0x89,
+ (byte) 0x50,
+ (byte) 0x4E,
+ (byte) 0x47,
+ (byte) 0x0D,
+ (byte) 0x0A,
+ (byte) 0x1A,
+ (byte) 0x0A
+ };
+
+ private static final int PNG_HEADER_SIZE = PNG_HEADER.length;
+
+ @Override
+ public String probeContentType(final Path path) throws IOException {
+ final byte[] buf = new byte[PNG_HEADER_SIZE];
+
+ try (final InputStream in = Files.newInputStream(path); ) {
+ if (in.read(buf) != PNG_HEADER_SIZE) {
+ return null;
+ }
+ }
+
+ return Arrays.equals(buf, PNG_HEADER) ? "image/png" : null;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
new file mode 100644
index 0000000..7b78157
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
@@ -0,0 +1,177 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FilesTest extends DesugaredLibraryTestBase {
+
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines(
+ "bytes written: 11",
+ "String written: Hello World",
+ "bytes read: 11",
+ "String read: Hello World",
+ "null",
+ "true",
+ "unsupported");
+ private static final String EXPECTED_RESULT_26 =
+ StringUtils.lines(
+ "bytes written: 11",
+ "String written: Hello World",
+ "bytes read: 11",
+ "String read: Hello World",
+ "true",
+ "true",
+ "true");
+
+ private final TestParameters parameters;
+ private final boolean shrinkDesugaredLibrary;
+
+ @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ public static List<Object[]> data() {
+ // Skip Android 4.4.4 due to missing libjavacrypto.
+ return buildParameters(
+ BooleanUtils.values(),
+ getTestParameters()
+ .withDexRuntime(Version.V4_0_4)
+ .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+ .withAllApiLevels()
+ .build());
+ }
+
+ private String getExpectedResult() {
+ return parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O)
+ ? EXPECTED_RESULT_26
+ : EXPECTED_RESULT;
+ }
+
+ public FilesTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.parameters = parameters;
+ }
+
+ private LibraryDesugaringTestConfiguration pathConfiguration() {
+ return LibraryDesugaringTestConfiguration.builder()
+ .setMinApi(parameters.getApiLevel())
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingWithPath()))
+ .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+ .withKeepRuleConsumer()
+ .build();
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .withArt6Plus64BitsLib()
+ .withArtFrameworks()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(getExpectedResult());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForR8(Backend.DEX)
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(TestClass.class)
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .withArt6Plus64BitsLib()
+ .withArtFrameworks()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(getExpectedResult());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) throws Throwable {
+ Path path = Files.createTempFile("example", ".txt");
+ readWrite(path);
+
+ PosixFileAttributeView view = Files.getFileAttributeView(path, PosixFileAttributeView.class);
+ if (view != null) {
+ System.out.println(
+ view.readAttributes().permissions().contains(PosixFilePermission.OWNER_READ));
+ } else {
+ System.out.println("null");
+ }
+
+ BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class);
+ if (attributes != null) {
+ System.out.println(attributes.isRegularFile());
+ } else {
+ System.out.println("null");
+ }
+
+ try {
+ PosixFileAttributes posixAttributes = Files.readAttributes(path, PosixFileAttributes.class);
+ if (attributes != null) {
+ System.out.println(
+ posixAttributes.permissions().contains(PosixFilePermission.OWNER_READ));
+ } else {
+ System.out.println("null");
+ }
+ } catch (UnsupportedOperationException e) {
+ System.out.println("unsupported");
+ }
+ }
+
+ private static void readWrite(Path path) throws IOException {
+ try (SeekableByteChannel channel =
+ Files.newByteChannel(path, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
+ String toWrite = "Hello World";
+
+ // Write the String toWrite into the channel.
+ ByteBuffer byteBuffer = ByteBuffer.wrap(toWrite.getBytes());
+ int write = channel.write(byteBuffer);
+ System.out.println("bytes written: " + write);
+ System.out.println("String written: " + toWrite);
+
+ // Read the String toWrite from the channel.
+ channel.position(0);
+ ByteBuffer byteBuffer2 = ByteBuffer.allocate(write);
+ int read = channel.read(byteBuffer2);
+ System.out.println("bytes read: " + read);
+ System.out.println("String read: " + new String(byteBuffer2.array()));
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/GoogleIcon.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/GoogleIcon.java
new file mode 100644
index 0000000..ce0be4d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/GoogleIcon.java
@@ -0,0 +1,168 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
+
+public class GoogleIcon {
+ static final byte[] GOOGLE_ICON_PNG =
+ new byte[] {
+ -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 1, 0, 0, 0, 1, 0, 8, 3,
+ 0, 0, 0, 107, -84, 88, 84, 0, 0, 2, -21, 80, 76, 84, 69, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 10, 33, -74, 0, 0,
+ 0, -8, 116, 82, 78, 83, 0, 0, 14, -25, -109, -6, -3, 5, 1, 22, -4, 3, -34, 47, -2, -33, -27,
+ -13, 4, -5, 20, 16, 13, -19, -12, -18, 21, -10, -30, 18, 2, 7, -97, -99, -121, 42, 6, -114,
+ 35, -35, -123, 68, -65, -26, -119, -21, -29, 45, 8, -38, 59, -96, -56, -14, -17, 10, -43,
+ 108, -16, -85, -55, 28, -22, 52, -46, 115, 112, 93, 26, 17, -52, -58, 36, 75, 27, -103, -15,
+ -83, 23, -95, 84, -64, 78, -66, -105, 34, -127, -117, 99, -60, -101, 40, 79, -54, -91, 44,
+ -126, 89, -24, -128, -7, 15, -39, 70, -80, 33, -111, 24, -53, 88, 110, 60, -122, -87, 90,
+ 25, 9, -41, -59, -84, -108, -102, -75, 58, -31, 51, -61, 113, -20, 57, 122, -74, 29, -113,
+ 54, 87, -107, -104, -73, 74, 39, -48, -50, -32, 65, -86, -67, 83, -76, -70, -23, 114, 71,
+ -71, 119, -100, 11, 111, 127, -110, -37, 50, 73, 69, 86, -9, -11, 116, 66, -68, 19, 107,
+ -81, 63, -89, -124, 37, -79, 53, 56, -98, -62, 46, 38, 12, 64, 117, 106, 77, 32, 126, -49,
+ -69, -125, 123, -93, -92, 91, -106, 67, 62, -57, 95, 125, -82, -90, 97, 100, 121, 104, -44,
+ -77, -78, -36, 85, 30, 92, 82, 109, 102, -115, 103, 94, 41, -40, -47, -94, 105, 48, 124,
+ -63, 120, -8, 118, 43, 61, -72, -116, 31, -45, -51, 72, 76, -28, -42, -118, 55, 101, -29,
+ -118, -16, -44, 0, 0, 9, 41, 73, 68, 65, 84, 120, 94, -20, -64, -127, 0, 0, 0, 0, -61, -96,
+ -5, 83, -33, 96, 4, -75, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -100, -68, -69, -118, 110, -28,
+ -56, -30, 56, -68, -41, -79, 100, 102, 102, 26, -77, -57, 8, 51, -29, -79, 61, 100, 28, 102,
+ 102, 102, 102, 102, 102, 74, -122, 25, 2, 67, 73, 6, -126, -80, 97, 102, -50, 38, 89, 102,
+ -90, -1, -29, -66, -84, -114, -70, -69, 74, 114, 89, -3, -94, 43, 125, -49, 122, -47, -81,
+ 79, 67, -99, 62, 125, -117, 92, -107, -102, -42, 41, -42, 71, 89, 99, -17, 52, 15, 9, -48,
+ 105, -40, -115, 94, -101, 119, 118, 125, 116, 92, -25, -36, -28, -16, -121, 20, 77, -114,
+ 56, -80, -39, -121, 127, -128, -56, 49, -117, -77, 15, 31, -8, 29, 92, 112, 116, 59, 17,
+ -13, 0, -3, -113, -84, -22, 28, 5, -41, 84, 94, 36, -30, 29, 32, 102, -57, -118, -115, 112,
+ 85, -16, -121, 65, -60, 59, 64, 73, 118, 49, 92, 86, 51, -79, -111, -120, 117, -128, -14,
+ -82, 22, -72, -52, -102, -34, 66, -60, 58, -64, -70, 126, -48, -78, 86, -121, 23, 86, 91,
+ -95, -22, 88, 57, 17, -21, 0, 1, -66, -102, -93, 31, -11, 118, -34, -32, -84, -128, -40,
+ -40, -128, -84, -25, 111, 53, 7, 66, 42, -12, -77, 17, -66, 54, 43, 125, 7, 18, -15, 14,
+ -80, 56, 25, 54, 40, -52, 44, 33, -115, -112, -20, 56, -56, 116, -1, 3, 9, -72, 6, -120,
+ 126, 21, 54, -120, -97, 24, 64, 6, 95, -82, -76, 66, 34, 126, -96, -89, 4, 88, 80, 6, 27,
+ 20, 76, 32, -119, 103, 58, 67, 34, -12, 91, -49, 8, -16, -31, 21, -40, 96, -74, 31, 73, -91,
+ -84, -128, -52, 25, 79, 8, -16, 107, -40, -67, 75, 14, -51, -122, -52, 115, -4, 3, -28, -63,
+ -18, -49, -28, -60, 8, -56, -52, -29, 30, 96, 10, -20, 94, -10, 39, 103, 86, 65, -30, 74,
+ 57, -17, 0, 93, 96, -41, 119, 22, 57, 21, 121, 12, 18, -55, 75, 56, 7, 104, -75, -62, 110,
+ 51, -75, -95, 127, 50, 36, -74, -8, -13, 13, -48, -78, 17, 118, -123, 62, -44, -106, -4, 80,
+ 72, 124, -61, 54, -128, -33, 114, 104, -68, 66, 2, -75, 91, 65, -43, 44, -82, 1, -90, 64,
+ 35, 106, 12, -75, -51, 39, 12, 18, -117, -104, 6, 8, -103, 10, -115, 90, 82, -79, 3, 50,
+ 107, 88, 6, -16, 47, -128, 86, 30, -87, -16, 31, 5, -119, -35, 44, 3, 124, 1, -99, 61, -92,
+ -28, 77, 72, -124, 94, 96, 24, -96, -61, 39, -48, -102, 58, -116, -44, 12, -126, 68, 31,
+ -122, 1, 22, 67, 39, 121, 41, -87, 121, 30, 18, 29, 99, -40, 5, 72, -99, 11, -99, 113, -92,
+ 40, -78, 51, 36, -114, -80, 11, -16, 22, -12, -74, -112, -86, -121, 33, 49, -128, 93, -128,
+ 116, -24, -35, 36, 85, -67, -29, 33, -54, -19, -64, 44, 64, 76, 71, -24, 61, 77, -54, 102,
+ 66, 100, -51, 98, 22, 96, 44, 12, 78, -111, -78, 73, -112, -40, -63, 44, 64, 31, 24, -92,
+ -109, -78, -128, -66, 16, 77, -28, 21, 32, -88, -77, -8, 60, -81, 110, 55, 68, -29, 121, 5,
+ 24, 102, -127, -63, 9, 82, -41, 19, -94, 2, 94, 1, 6, -61, -88, -119, -44, -83, -125, 104,
+ 31, -81, 0, 31, -63, 104, -19, 82, 82, -74, -76, 24, -126, 50, 63, 86, 1, 50, 96, 116, -75,
+ -114, -44, 29, -123, 32, -84, -108, 85, -128, 63, 65, -80, -119, -44, 77, 100, 31, 96, 28,
+ 4, 31, -112, -70, 35, 16, -108, 69, 114, 10, -112, -38, 25, -126, -39, -92, 46, 36, 20, 70,
+ 47, 17, -89, 0, -111, -45, 33, 88, 79, -22, -94, -85, 97, 52, -124, 85, -128, -96, 101, 16,
+ 36, 60, 70, 106, -28, 1, 95, 99, 21, -128, -10, 65, -12, 38, -87, 91, 15, -93, -31, -68, 2,
+ 12, -126, 40, -113, -52, 44, 8, 47, -13, 10, -80, 8, -94, -71, -92, 110, 0, 12, 2, -57, -16,
+ 10, -112, 9, -111, -27, 62, 41, 27, 42, 62, 8, -14, 10, -48, 11, 18, -41, 72, -103, 47, 12,
+ 70, 19, -81, 0, -65, -126, -60, 92, 127, 82, -75, 19, 6, -83, -52, 2, 116, 42, -122, 40,
+ -76, 27, -87, 122, 26, 122, -59, -89, -103, 5, -96, -82, -112, 24, 74, -86, -6, 65, 47,
+ -109, -72, 5, 120, 7, 18, 9, 1, -92, 104, 20, 116, -110, 94, 96, 23, 96, 78, 4, 36, 54,
+ -109, -102, -76, 48, -24, -68, 65, -20, 2, -56, -49, -127, -62, 105, -92, 100, -42, 84, 104,
+ -43, -44, 49, 12, 112, 9, 50, 63, 37, 37, 99, -95, -77, -127, 24, 6, 8, -38, 15, -119, -124,
+ 6, 82, 113, 14, 90, -93, 34, 57, 6, -96, -53, -112, -87, 32, 5, 29, -50, 67, -93, -26, 62,
+ -79, 12, 16, 52, 14, 50, -113, 80, -37, 102, 64, -21, 11, -30, 25, -128, -98, -127, 76, 88,
+ 10, -75, 105, 11, 52, -34, 37, -82, 1, -24, 20, 100, 14, 81, 91, 14, 66, 99, 39, -15, 13,
+ -48, 24, -20, -46, -99, -96, -12, -25, -80, 75, 39, -58, 1, -24, 70, 20, 100, -34, 33, -89,
+ 86, -62, -18, -108, 63, -21, 0, 52, 31, 50, -127, -109, -56, -119, 30, -80, -37, -58, -2,
+ -117, -111, 108, -56, 88, 63, 38, -121, 78, -62, -18, 36, -79, 15, 64, -93, 33, -11, 93, 7,
+ -110, -118, -47, -84, -125, -29, 39, -111, 7, 4, -96, -95, -112, 90, -66, -99, 36, -58, 46,
+ -125, 13, 114, -97, 34, -113, 8, 64, -61, 33, 101, -15, -51, 33, -125, -21, -85, 97, 119,
+ -94, -127, 60, 36, 0, 45, 78, -128, 84, 85, -59, -116, 88, -78, -95, -100, -57, -105, 67,
+ 35, 59, -110, 60, 38, 0, 101, 21, -64, -127, -28, 39, 94, -100, -108, -65, 102, -63, 63,
+ 126, -71, -77, 54, 73, 120, 13, -30, 57, 1, 40, -75, 103, 61, -38, 101, 33, -15, 14, 32,
+ -38, 122, 46, 2, -22, 86, 17, -5, 0, -94, -37, 35, -62, -95, 104, -67, 31, -9, 0, 114, 41,
+ -33, 127, 90, 3, 5, 17, -9, -119, 113, 0, -25, 26, 6, -82, -84, -115, 67, 27, 110, 17, -37,
+ 0, 74, 18, -69, 13, -36, 80, 52, -6, -3, 21, 93, 95, -37, -107, 121, -19, -85, 93, 48, -118,
+ -24, -19, -63, 1, 68, 67, 96, -76, -101, -68, 41, -64, 83, 16, 12, -9, -86, 0, -25, 32, -8,
+ -42, -101, 2, -8, 77, -121, -32, -65, -34, 20, -32, 118, 20, 4, 103, -67, 41, -64, 35, 16,
+ -83, -10, -90, 0, 95, 65, 20, 81, -25, 69, 1, 70, 66, 98, -101, 23, 5, 120, 29, 18, -106,
+ 63, 122, -9, 53, 0, 40, 110, -15, -102, 0, 99, 2, 33, -13, 121, -106, -73, 4, 40, 13, -125,
+ -44, -28, 124, 47, 9, 64, -65, -128, -100, -27, -116, -105, 4, 104, -123, 35, 3, 98, -67,
+ 34, 64, -38, -113, 112, -28, 111, 37, -34, 16, -128, 70, -62, -95, -124, 121, -34, 16, -64,
+ 111, 63, 28, 43, 10, -14, -4, 0, 84, 110, -123, 99, 39, -22, 60, 63, 0, 45, -124, 19, -63,
+ -37, 61, 63, -128, -33, 93, 56, 81, 53, -48, -29, 3, 80, 98, 46, -100, -23, -31, -47, 1, -4,
+ -90, -11, -34, 27, -78, 16, 78, 101, 123, 96, -128, -46, -70, 110, 99, 31, -49, -84, -40,
+ 50, -82, 108, 114, 68, 32, -38, 50, 62, -51, -125, 2, 68, -66, 48, 99, -61, -24, -126, -36,
+ 8, -76, -57, -22, 7, -98, 17, 96, 90, -7, -61, -117, -106, 37, -63, 5, 67, 124, -8, 7, -104,
+ 48, -1, 78, 33, 92, 54, -28, 1, -17, 0, 23, -122, 55, 5, -62, -108, -43, 126, 124, 3, 44,
+ -23, -46, 28, 10, 7, 44, 113, -63, -5, 11, -18, -68, -97, -79, 106, 116, -6, -94, 71, -29,
+ -31, 68, 58, -41, 0, 33, 111, 108, -124, 68, 84, -14, 111, 50, 126, 59, 111, -63, -19, -24,
+ 82, -51, 79, -101, -31, -60, 71, 44, 3, 116, -69, 105, -127, -96, -2, -47, -123, 95, -113,
+ 57, 77, -94, -76, 34, 56, 22, 122, -119, 95, -128, 97, 25, 81, 48, -22, 62, 98, 70, 52, 57,
+ -76, -25, 0, 28, 42, -114, 102, 22, -96, -61, -17, 19, 96, 112, 124, -24, -126, 32, 114,
+ -86, -31, 61, 56, 84, -63, 43, -64, 83, -75, 48, -104, -34, -77, 63, -75, -19, -38, 84, 56,
+ 114, -112, 83, -128, -109, -58, -1, -79, -74, -53, 105, 82, -14, 86, 25, 28, -88, 76, 101,
+ 19, -96, 113, 5, -12, -84, -37, -94, 73, 85, -64, 19, 112, 96, 48, -105, 0, -61, -10, 67,
+ 111, -6, 117, 106, -113, 41, -112, 27, -60, 36, -64, -124, 3, -48, -5, 44, -111, -38, -25,
+ 114, 95, -56, 88, 67, 88, 4, -56, -6, 39, -12, -6, -92, 82, 123, 61, 25, 12, -103, 76, 14,
+ 1, -74, 6, 67, 111, 23, -71, -32, 47, 77, -112, -24, -50, 96, -81, -79, 78, -107, -48, -101,
+ -23, 79, -82, 72, 25, 4, 81, -32, 94, -9, 15, -112, 1, -67, -13, 49, -28, -102, -40, -61,
+ 16, -11, 114, -5, 0, -117, -95, 23, -6, 12, -71, 106, -38, -37, 16, 108, 115, -9, 0, 115,
+ -22, -123, -25, 87, -41, 45, -55, -123, -47, 110, 119, 15, -112, 1, -67, -92, 28, 50, -95,
+ 91, 18, 12, -2, -22, -17, -34, 1, 46, 4, 10, -61, 96, 77, -23, 2, -125, -16, 7, -18, 29,
+ -96, 31, 12, -14, -55, -100, 65, -48, -85, 14, 112, -21, 0, 89, 81, -48, 43, -18, 68, -26,
+ 116, 11, -124, 78, 124, -99, 91, 7, -8, 14, 6, 93, -55, -84, 39, -96, -109, -76, -43, -99,
+ 3, 44, 93, 11, -125, 103, -55, -84, 124, -24, 68, 52, -72, 115, -128, -21, -110, -11, -85,
+ 89, 105, -63, -48, -22, -40, -24, -50, 1, -118, 96, -12, 36, -103, -106, 1, -83, -49, -3,
+ -36, 57, -64, 40, 24, 88, -9, -110, 105, 35, -95, 53, -118, -36, 56, -128, -80, -87, 2, 44,
+ 57, 100, 90, 57, -76, 42, -36, 57, 64, 73, -88, 100, -15, 102, 90, 75, 20, 52, 122, -70,
+ 115, -128, -65, 67, -80, -114, 76, 91, 82, 5, -115, 5, -18, 28, -96, 23, 4, -83, 100, 90,
+ 98, 2, -20, -114, -5, -72, 115, -128, -97, 65, -80, -127, 76, -101, 83, 5, -69, 126, -60,
+ 44, -64, 120, 50, 45, -57, 2, -69, -41, -119, -39, 41, 16, -100, 70, 102, 109, -126, 93, 92,
+ -118, 91, 7, -72, 8, 81, 57, -103, -11, 61, -20, -6, -112, 91, 7, -72, 7, -47, 80, 50, -53,
+ 87, 120, 45, -64, -32, 65, 72, 55, 71, -43, 28, -1, 125, -80, -63, 76, 114, -17, 0, -76, 30,
+ -94, 91, 100, 78, 73, 32, 108, -84, -21, -36, 61, 64, -98, 124, -53, 88, 83, -118, -124,
+ -55, 114, 110, 28, 96, 13, 36, 62, 37, 51, 26, 39, -61, 38, -82, -63, -19, 3, -8, -3, 11,
+ 18, -13, -55, -124, -77, -80, -63, 72, 6, -13, 3, -98, -123, -124, 37, -97, 92, -42, 82, 5,
+ -101, -9, -120, 65, -128, -60, 56, 72, -60, 61, 73, 46, 74, 29, 2, -101, -32, 68, 14, 1,
+ -24, 69, -56, -44, 111, 34, -41, -4, 27, 54, 73, -1, 33, 22, 1, 124, -62, 32, -45, -9, 107,
+ 114, 69, 79, -19, 126, -117, 60, 2, -48, 88, -56, 77, 9, 34, 117, -30, 112, -51, 46, -60,
+ 37, 0, -19, -126, 92, 65, 8, -75, 79, -121, -39, -62, 103, 51, 44, 2, 44, -83, -123, 92,
+ -46, -62, 104, 106, -121, 123, 119, -123, -29, -49, 35, 0, 125, 25, 6, 7, -110, -97, 85, 78,
+ 16, 51, 37, 30, 54, 87, -25, 17, -85, 0, 52, 33, 28, -114, -124, 23, -107, -112, -126, -57,
+ 122, 6, -61, 6, -71, 107, -120, 89, 0, 42, 9, -125, 67, 81, -121, -97, 107, 33, -89, 82,
+ -73, 103, 107, 11, -34, 89, 66, -20, 2, -48, -84, 90, 56, 113, -91, 57, -77, 117, -85, 63,
+ 73, 5, -52, 40, 122, 9, 26, -15, 15, -13, -100, 31, 16, 91, 1, -25, -30, -69, 31, -102, -40,
+ -21, -58, 15, 115, 98, -3, -2, 127, -55, -9, -23, 29, -78, 103, 126, -97, -26, 56, -24, -68,
+ 124, -113, -19, -4, -128, -111, 27, -47, -74, -64, -66, -31, 101, -35, -101, 42, 43, -25,
+ 118, 63, -1, 80, 4, 4, 97, 31, 112, -98, 31, -112, 115, 8, -26, -44, -97, 77, 97, 62, 63,
+ -96, -75, 18, -82, 43, 124, -91, 55, -1, 17, 26, 65, -109, 92, 77, -80, -17, 76, -94, 103,
+ 12, 81, -15, -65, -40, -17, 42, -38, -21, -8, -128, 75, -111, 30, 52, 71, 40, -89, -57, 114,
+ 11, -44, -123, -33, -100, -105, -24, 113, -77, -60, 126, 120, 124, 102, 56, 20, 36, -36,
+ -51, -53, -113, 33, 1, -61, 0, 34, -97, 77, -33, 12, 104, -22, 8, 71, 66, -21, -101, 94,
+ -19, 113, -80, 63, 9, 56, 7, 16, 61, 22, 50, 120, -2, -120, -15, -57, -26, 46, 91, 59, 57,
+ -82, -70, -90, -90, -70, 99, 97, -16, 39, -51, 71, -45, -13, 62, -34, 51, 33, -123, 4, 28,
+ 3, 40, 10, -22, 52, 45, 58, 96, 78, -1, -128, -108, -40, 82, 127, 114, -55, -1, -38, -127,
+ 3, 1, 0, 0, 0, -122, 65, -9, -89, -66, -63, 8, 106, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,
+ -31, -37, 22, 69, 99, -29, 53, -11, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126
+ };
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/InputStreamTransferToTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/InputStreamTransferToTest.java
index 77f16d2..bee154b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/InputStreamTransferToTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/InputStreamTransferToTest.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
@@ -41,21 +44,24 @@
this.parameters = parameters;
}
+ private LibraryDesugaringTestConfiguration pathConfiguration() {
+ return LibraryDesugaringTestConfiguration.builder()
+ .setMinApi(parameters.getApiLevel())
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingWithPath()))
+ .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+ .withKeepRuleConsumer()
+ .build();
+ }
+
@Test
public void testD8() throws Exception {
Assume.assumeTrue(isJDK11DesugaredLibrary());
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForD8(parameters.getBackend())
.addLibraryFiles(getLibraryFile())
.addProgramFiles(INPUT_JAR)
.setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
+ .enableCoreLibraryDesugaring(pathConfiguration())
.run(parameters.getRuntime(), MAIN_CLASS)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
@@ -63,19 +69,12 @@
@Test
public void testR8() throws Exception {
Assume.assumeTrue(isJDK11DesugaredLibrary());
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(parameters.getBackend())
.addLibraryFiles(getLibraryFile())
.addProgramFiles(INPUT_JAR)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_CLASS)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
+ .enableCoreLibraryDesugaring(pathConfiguration())
.run(parameters.getRuntime(), MAIN_CLASS)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/PathTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/PathTest.java
new file mode 100644
index 0000000..3065b0f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/PathTest.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class PathTest extends DesugaredLibraryTestBase {
+
+ private static final String EXPECTED_RESULT = StringUtils.lines("x.txt", "dir", "dir/x.txt", "/");
+ private final TestParameters parameters;
+ private final boolean shrinkDesugaredLibrary;
+
+ @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ }
+
+ public PathTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.parameters = parameters;
+ }
+
+ private LibraryDesugaringTestConfiguration pathConfiguration() {
+ return LibraryDesugaringTestConfiguration.builder()
+ .setMinApi(parameters.getApiLevel())
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingWithPath()))
+ .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+ .withKeepRuleConsumer()
+ .build();
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(PathTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForR8(Backend.DEX)
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(PathTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(TestClass.class)
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ File file = new File("x.txt");
+ Path path1 = file.toPath();
+ System.out.println(path1);
+ Path path2 = Paths.get("dir/");
+ System.out.println(path2);
+ Path resolve = path2.resolve(path1);
+ System.out.println(resolve);
+ System.out.println(resolve.getFileSystem().getSeparator());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java
index 1b9581a..b55ebae 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java
@@ -4,7 +4,11 @@
package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.transformers.MethodTransformer;
import com.android.tools.r8.utils.BooleanUtils;
@@ -42,21 +46,24 @@
this.parameters = parameters;
}
+ private LibraryDesugaringTestConfiguration pathConfiguration() {
+ return LibraryDesugaringTestConfiguration.builder()
+ .setMinApi(parameters.getApiLevel())
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingWithPath()))
+ .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+ .withKeepRuleConsumer()
+ .build();
+ }
+
@Test
public void testD8() throws Exception {
Assume.assumeTrue(isJDK11DesugaredLibrary());
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForD8(parameters.getBackend())
.addLibraryFiles(getLibraryFile())
.addProgramClassFileData(getProgramClassFileData())
.setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
+ .enableCoreLibraryDesugaring(pathConfiguration())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -64,19 +71,12 @@
@Test
public void testR8() throws Exception {
Assume.assumeTrue(isJDK11DesugaredLibrary());
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(Backend.DEX)
.addLibraryFiles(getLibraryFile())
.addProgramClassFileData(getProgramClassFileData())
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(TestClass.class)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
+ .enableCoreLibraryDesugaring(pathConfiguration())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index f107b2a..ff80b66 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.ApiLevelRange;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecification;
@@ -80,21 +81,18 @@
MultiAPILevelHumanDesugaredLibrarySpecification humanSpec1,
MultiAPILevelHumanDesugaredLibrarySpecification humanSpec2) {
assertTopLevelFlagsEquals(humanSpec1.getTopLevelFlags(), humanSpec2.getTopLevelFlags());
- assertFlagMapEquals(
- humanSpec1.getCommonFlagsForTesting(), humanSpec2.getCommonFlagsForTesting());
- assertFlagMapEquals(
- humanSpec1.getLibraryFlagsForTesting(), humanSpec2.getLibraryFlagsForTesting());
- assertFlagMapEquals(
- humanSpec1.getProgramFlagsForTesting(), humanSpec2.getProgramFlagsForTesting());
+ assertFlagMapEquals(humanSpec1.getCommonFlags(), humanSpec2.getCommonFlags());
+ assertFlagMapEquals(humanSpec1.getLibraryFlags(), humanSpec2.getLibraryFlags());
+ assertFlagMapEquals(humanSpec1.getProgramFlags(), humanSpec2.getProgramFlags());
}
private void assertFlagMapEquals(
- Map<Integer, HumanRewritingFlags> commonFlags1,
- Map<Integer, HumanRewritingFlags> commonFlags2) {
+ Map<ApiLevelRange, HumanRewritingFlags> commonFlags1,
+ Map<ApiLevelRange, HumanRewritingFlags> commonFlags2) {
assertEquals(commonFlags1.size(), commonFlags2.size());
- for (int integer : commonFlags1.keySet()) {
- assertTrue(commonFlags2.containsKey(integer));
- assertFlagsEquals(commonFlags1.get(integer), commonFlags2.get(integer));
+ for (ApiLevelRange range : commonFlags1.keySet()) {
+ assertTrue(commonFlags2.containsKey(range));
+ assertFlagsEquals(commonFlags1.get(range), commonFlags2.get(range));
}
}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
index 5b700d5..ee0e845 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
@@ -138,7 +138,7 @@
}
@Test(expected = CompilationFailedException.class)
- @IgnoreForRangeOfVmVersions(from = Version.V7_0_0, to = Version.V13_MASTER) // No desugaring
+ @IgnoreForRangeOfVmVersions(from = Version.V7_0_0, to = Version.V13_0_0) // No desugaring
public void testInvokeDefault1() throws Exception {
ensureSameOutput(
TestMainDefault1.class.getCanonicalName(),
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java
index 45a3be4..71e7df5 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java
@@ -47,28 +47,6 @@
}
@Test
- public void testPropagationFromFeature() throws Exception {
- ThrowingConsumer<R8TestCompileResult, Exception> ensureGetFromFeatureGone =
- r8TestCompileResult -> {
- // Ensure that getFromFeature from FeatureClass is inlined into the run method.
- ClassSubject clazz = r8TestCompileResult.inspector().clazz(FeatureClass.class);
- assertThat(clazz.uniqueMethodWithName("getFromFeature"), not(isPresent()));
- };
- ProcessResult processResult =
- testDexSplitter(
- parameters,
- ImmutableSet.of(BaseSuperClass.class),
- ImmutableSet.of(FeatureClass.class),
- FeatureClass.class,
- EXPECTED,
- ensureGetFromFeatureGone,
- TestShrinkerBuilder::noMinification);
- // We expect art to fail on this with the dex splitter, see b/122902374
- assertNotEquals(processResult.exitCode, 0);
- assertTrue(processResult.stderr.contains("NoClassDefFoundError"));
- }
-
- @Test
public void testOnR8Splitter() throws IOException, CompilationFailedException {
assumeTrue(parameters.isDexRuntime());
ProcessResult processResult =
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java
index 96220f8..53af2b6 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java
@@ -48,31 +48,6 @@
}
@Test
- public void testInliningFromFeature() throws Exception {
- ThrowingConsumer<R8TestCompileResult, Exception> ensureGetFromFeatureGone =
- r8TestCompileResult -> {
- // Ensure that getFromFeature from FeatureClass is inlined into the run method.
- ClassSubject clazz = r8TestCompileResult.inspector().clazz(FeatureClass.class);
- assertThat(clazz.uniqueMethodWithName("getFromFeature"), not(isPresent()));
- };
- Consumer<R8FullTestBuilder> configurator =
- r8FullTestBuilder ->
- r8FullTestBuilder.enableNoVerticalClassMergingAnnotations().noMinification();
- ProcessResult processResult =
- testDexSplitter(
- parameters,
- ImmutableSet.of(BaseSuperClass.class),
- ImmutableSet.of(FeatureClass.class),
- FeatureClass.class,
- EXPECTED,
- ensureGetFromFeatureGone,
- configurator);
- // We expect art to fail on this with the dex splitter, see b/122902374
- assertNotEquals(processResult.exitCode, 0);
- assertTrue(processResult.stderr.contains("NoClassDefFoundError"));
- }
-
- @Test
public void testOnR8Splitter() throws IOException, CompilationFailedException {
assumeTrue(parameters.isDexRuntime());
ThrowableConsumer<R8FullTestBuilder> configurator =
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java
index 38d19da..a2e1b1d 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java
@@ -46,28 +46,6 @@
}
@Test
- public void testPropagationFromFeature() throws Exception {
- ThrowingConsumer<R8TestCompileResult, Exception> ensureGetFromFeatureGone =
- r8TestCompileResult -> {
- // Ensure that getFromFeature from FeatureClass is inlined into the run method.
- ClassSubject clazz = r8TestCompileResult.inspector().clazz(FeatureClass.class);
- assertThat(clazz.uniqueMethodWithName("getFromFeature"), not(isPresent()));
- };
- ProcessResult processResult =
- testDexSplitter(
- parameters,
- ImmutableSet.of(BaseSuperClass.class),
- ImmutableSet.of(FeatureClass.class, FeatureEnum.class),
- FeatureClass.class,
- EXPECTED,
- ensureGetFromFeatureGone,
- builder -> builder.enableInliningAnnotations().noMinification());
- // We expect art to fail on this with the dex splitter, see b/122902374
- assertNotEquals(processResult.exitCode, 0);
- assertTrue(processResult.stderr.contains("NoClassDefFoundError"));
- }
-
- @Test
public void testOnR8Splitter() throws IOException, CompilationFailedException {
assumeTrue(parameters.isDexRuntime());
ProcessResult processResult =
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
index 71ddab8..a7d137f 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
@@ -48,43 +48,6 @@
}
@Test
- public void testInliningFromFeature() throws Exception {
- // Static merging is based on sorting order, we assert that we merged to the feature.
- ThrowingConsumer<R8TestCompileResult, Exception> ensureMergingToFeature =
- r8TestCompileResult -> {
- ClassSubject clazz = r8TestCompileResult.inspector().clazz(AFeatureWithStatic.class);
- assertEquals(2, clazz.allMethods().size());
- assertThat(clazz.uniqueMethodWithName("getBase42"), isPresent());
- assertThat(clazz.uniqueMethodWithName("getFoobar"), isPresent());
- };
- Consumer<R8FullTestBuilder> configurator =
- r8FullTestBuilder ->
- r8FullTestBuilder
- .addOptionsModification(
- options ->
- options.testing.horizontalClassMergingTarget =
- (appView, candidates, target) -> candidates.iterator().next())
- .addHorizontallyMergedClassesInspector(
- inspector ->
- inspector.assertMergedInto(BaseWithStatic.class, AFeatureWithStatic.class))
- .enableNoVerticalClassMergingAnnotations()
- .enableInliningAnnotations()
- .noMinification();
- ProcessResult processResult =
- testDexSplitter(
- parameters,
- ImmutableSet.of(BaseClass.class, BaseWithStatic.class),
- ImmutableSet.of(FeatureClass.class, AFeatureWithStatic.class),
- FeatureClass.class,
- EXPECTED,
- ensureMergingToFeature,
- configurator);
- // We expect art to fail on this with the dex splitter.
- assertNotEquals(processResult.exitCode, 0);
- assertTrue(processResult.stderr.contains("NoClassDefFoundError"));
- }
-
- @Test
public void testOnR8Splitter() throws IOException, CompilationFailedException {
assumeTrue(parameters.isDexRuntime());
ThrowableConsumer<R8FullTestBuilder> configurator =
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
deleted file mode 100644
index e90e0ab..0000000
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
+++ /dev/null
@@ -1,484 +0,0 @@
-// Copyright (c) 2017, 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.dexsplitter;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.DexSplitterHelper;
-import com.android.tools.r8.ExtractMarker;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.R8;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.ResourceException;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
-import com.android.tools.r8.dex.Marker;
-import com.android.tools.r8.dexsplitter.DexSplitter.Options;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-public class DexSplitterTests {
-
- private static final String CLASS_DIR =
- ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR + "classes/dexsplitsample";
- private static final String CLASS1_CLASS = CLASS_DIR + "/Class1.class";
- private static final String CLASS2_CLASS = CLASS_DIR + "/Class2.class";
- private static final String CLASS3_CLASS = CLASS_DIR + "/Class3.class";
- private static final String CLASS3_INNER_CLASS = CLASS_DIR + "/Class3$InnerClass.class";
- private static final String CLASS3_SYNTHETIC_CLASS = CLASS_DIR + "/Class3$1.class";
- private static final String CLASS4_CLASS = CLASS_DIR + "/Class4.class";
- private static final String CLASS4_LAMBDA_INTERFACE = CLASS_DIR + "/Class4$LambdaInterface.class";
- private static final String TEXT_FILE =
- ToolHelper.EXAMPLES_ANDROID_N_DIR + "dexsplitsample/TextFile.txt";
-
-
- @Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
- private Path createInput(boolean dontCreateMarkerInD8)
- throws IOException, CompilationFailedException {
- // Initial normal compile to create dex files.
- Path inputZip = temp.newFolder().toPath().resolve("input.zip");
- D8Command command =
- D8Command.builder()
- .setOutput(inputZip, OutputMode.DexIndexed)
- .addProgramFiles(Paths.get(CLASS1_CLASS))
- .addProgramFiles(Paths.get(CLASS2_CLASS))
- .addProgramFiles(Paths.get(CLASS3_CLASS))
- .addProgramFiles(Paths.get(CLASS3_INNER_CLASS))
- .addProgramFiles(Paths.get(CLASS3_SYNTHETIC_CLASS))
- .addProgramFiles(Paths.get(CLASS4_CLASS))
- .addProgramFiles(Paths.get(CLASS4_LAMBDA_INTERFACE))
- .build();
-
- DexSplitterHelper.runD8ForTesting(command, dontCreateMarkerInD8);
-
- return inputZip;
- }
-
- private void testMarker(boolean addMarkerToInput)
- throws CompilationFailedException, IOException, ResourceException, ExecutionException {
- Path inputZip = createInput(!addMarkerToInput);
-
- Path output = temp.newFolder().toPath().resolve("output");
- Files.createDirectory(output);
- Path splitSpec = createSplitSpec();
-
- DexSplitter.main(
- new String[] {
- "--input", inputZip.toString(),
- "--output", output.toString(),
- "--feature-splits", splitSpec.toString()
- });
-
- Path base = output.resolve("base").resolve("classes.dex");
- Path feature = output.resolve("feature1").resolve("classes.dex");
-
- for (Path path : new Path[] {inputZip, base, feature}) {
- Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(path);
- assertEquals(addMarkerToInput ? 1 : 0, markers.size());
- }
- }
-
- @Test
- public void testMarkerPreserved()
- throws CompilationFailedException, IOException, ResourceException, ExecutionException {
- testMarker(true);
- }
-
- @Test
- public void testMarkerNotAdded()
- throws CompilationFailedException, IOException, ResourceException, ExecutionException {
- testMarker(false);
- }
-
- /**
- * To test the file splitting we have 3 classes that we distribute like this: Class1 -> base
- * Class2 -> feature1 Class3 -> feature1
- *
- * <p>Class1 and Class2 works independently of each other, but Class3 extends Class1, and
- * therefore can't run without the base being loaded.
- */
- @Test
- public void splitFilesNoObfuscation()
- throws CompilationFailedException, IOException, FeatureMappingException {
- noObfuscation(false);
- noObfuscation(true);
- }
-
- private void noObfuscation(boolean useOptions)
- throws IOException, CompilationFailedException, FeatureMappingException {
- Path inputZip = createInput(false);
- Path output = temp.newFolder().toPath().resolve("output");
- Files.createDirectory(output);
- Path splitSpec = createSplitSpec();
-
- if (useOptions) {
- Options options = new Options();
- options.addInputArchive(inputZip.toString());
- options.setFeatureSplitMapping(splitSpec.toString());
- options.setOutput(output.toString());
- DexSplitter.run(options);
- } else {
- DexSplitter.main(
- new String[] {
- "--input", inputZip.toString(),
- "--output", output.toString(),
- "--feature-splits", splitSpec.toString()
- });
- }
-
- Path base = output.resolve("base").resolve("classes.dex");
- Path feature = output.resolve("feature1").resolve("classes.dex");
- validateUnobfuscatedOutput(base, feature);
- }
-
- private void validateUnobfuscatedOutput(Path base, Path feature) throws IOException {
- // Both classes should still work if we give all dex files to the system.
- for (String className : new String[] {"Class1", "Class2", "Class3"}) {
- ArtCommandBuilder builder = new ArtCommandBuilder();
- builder.appendClasspath(base.toString());
- builder.appendClasspath(feature.toString());
- builder.setMainClass("dexsplitsample." + className);
- String out = ToolHelper.runArt(builder);
- assertEquals(out, className + "\n");
- }
- // Individual classes should also work from the individual files.
- String className = "Class1";
- ArtCommandBuilder builder = new ArtCommandBuilder();
- builder.appendClasspath(base.toString());
- builder.setMainClass("dexsplitsample." + className);
- String out = ToolHelper.runArt(builder);
- assertEquals(out, className + "\n");
-
- className = "Class2";
- builder = new ArtCommandBuilder();
- builder.appendClasspath(feature.toString());
- builder.setMainClass("dexsplitsample." + className);
- out = ToolHelper.runArt(builder);
- assertEquals(out, className + "\n");
-
- className = "Class3";
- builder = new ArtCommandBuilder();
- builder.appendClasspath(feature.toString());
- builder.setMainClass("dexsplitsample." + className);
- try {
- ToolHelper.runArt(builder);
- assertFalse(true);
- } catch (AssertionError assertionError) {
- // We expect this to throw since base is not in the path and Class3 depends on Class1
- }
-
- className = "Class4";
- builder = new ArtCommandBuilder();
- builder.appendClasspath(feature.toString());
- builder.setMainClass("dexsplitsample." + className);
- try {
- ToolHelper.runArt(builder);
- assertFalse(true);
- } catch (AssertionError assertionError) {
- // We expect this to throw since base is not in the path and Class4 includes a lambda that
- // would have been pushed to base.
- }
- }
-
- private Path createSplitSpec() throws FileNotFoundException, UnsupportedEncodingException {
- Path splitSpec = temp.getRoot().toPath().resolve("split_spec");
- try (PrintWriter out = new PrintWriter(splitSpec.toFile(), "UTF-8")) {
- out.write(
- "dexsplitsample.Class1:base\n"
- + "dexsplitsample.Class2:feature1\n"
- + "dexsplitsample.Class3:feature1\n"
- + "dexsplitsample.Class4:feature1");
- }
- return splitSpec;
- }
-
- private List<String> getProguardConf() {
- return ImmutableList.of(
- "-keep class dexsplitsample.Class3 {",
- " public static void main(java.lang.String[]);",
- "}");
- }
-
- @Test
- public void splitFilesFromJar()
- throws IOException, CompilationFailedException, FeatureMappingException {
- for (boolean useOptions : new boolean[]{false, true}) {
- for (boolean explicitBase: new boolean[]{false, true}) {
- for (boolean renameBase: new boolean[]{false, true}) {
- splitFromJars(useOptions, explicitBase, renameBase);
- }
- }
- }
- }
-
- private void splitFromJars(boolean useOptions, boolean explicitBase, boolean renameBase)
- throws IOException, CompilationFailedException, FeatureMappingException {
- Path inputZip = createInput(false);
- Path output = temp.newFolder().toPath().resolve("output");
- Files.createDirectory(output);
- Path baseJar = temp.getRoot().toPath().resolve("base.jar");
- Path featureJar = temp.getRoot().toPath().resolve("feature1.jar");
- ZipOutputStream baseStream = new ZipOutputStream(Files.newOutputStream(baseJar));
- String name = "dexsplitsample/Class1.class";
- baseStream.putNextEntry(new ZipEntry(name));
- baseStream.write(Files.readAllBytes(Paths.get(CLASS1_CLASS)));
- baseStream.closeEntry();
- baseStream.close();
-
- ZipOutputStream featureStream = new ZipOutputStream(Files.newOutputStream(featureJar));
- name = "dexsplitsample/Class2.class";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(Files.readAllBytes(Paths.get(CLASS2_CLASS)));
- featureStream.closeEntry();
- name = "dexsplitsample/Class3.class";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(Files.readAllBytes(Paths.get(CLASS3_CLASS)));
- featureStream.closeEntry();
- name = "dexsplitsample/Class3$InnerClass.class";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(Files.readAllBytes(Paths.get(CLASS3_INNER_CLASS)));
- featureStream.closeEntry();
- name = "dexsplitsample/Class3$1.class";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(Files.readAllBytes(Paths.get(CLASS3_SYNTHETIC_CLASS)));
- featureStream.closeEntry();
- name = "dexsplitsample/Class4";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(Files.readAllBytes(Paths.get(CLASS4_CLASS)));
- featureStream.closeEntry();
- name = "dexsplitsample/Class4$LambdaInterface";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(Files.readAllBytes(Paths.get(CLASS4_LAMBDA_INTERFACE)));
- featureStream.closeEntry();
- featureStream.close();
- // Make sure that we can pass in a name for the output.
- String specificOutputName = "renamed";
- if (useOptions) {
- Options options = new Options();
- options.addInputArchive(inputZip.toString());
- options.setOutput(output.toString());
- if (explicitBase) {
- options.addBaseJar(baseJar.toString());
- } else if (renameBase){
- // Ensure that we can rename base (if people called a feature base)
- options.setBaseOutputName("base_renamed");
- }
- options.addFeatureJar(featureJar.toString(), specificOutputName);
- DexSplitter.run(options);
- } else {
- List<String> args = Lists.newArrayList(
- "--input",
- inputZip.toString(),
- "--output",
- output.toString(),
- "--feature-jar",
- featureJar.toString().concat(":").concat(specificOutputName));
- if (explicitBase) {
- args.add("--base-jar");
- args.add(baseJar.toString());
- } else if (renameBase) {
- args.add("--base-output-name");
- args.add("base_renamed");
- }
-
- DexSplitter.main(args.toArray(StringUtils.EMPTY_ARRAY));
- }
- String baseOutputName = explicitBase || !renameBase ? "base" : "base_renamed";
- Path base = output.resolve(baseOutputName).resolve("classes.dex");
- Path feature = output.resolve(specificOutputName).resolve("classes.dex");;
- validateUnobfuscatedOutput(base, feature);
- }
-
- @Test
- public void splitFilesObfuscation()
- throws CompilationFailedException, IOException, ExecutionException {
- // Initial normal compile to create dex files.
- Path inputDex = temp.newFolder().toPath().resolve("input.zip");
- Path proguardMap = temp.getRoot().toPath().resolve("proguard.map");
-
- R8.run(
- R8Command.builder()
- .setOutput(inputDex, OutputMode.DexIndexed)
- .addProgramFiles(Paths.get(CLASS1_CLASS))
- .addProgramFiles(Paths.get(CLASS2_CLASS))
- .addProgramFiles(Paths.get(CLASS3_CLASS))
- .addProgramFiles(Paths.get(CLASS3_INNER_CLASS))
- .addProgramFiles(Paths.get(CLASS3_SYNTHETIC_CLASS))
- .addProgramFiles(Paths.get(CLASS4_CLASS))
- .addProgramFiles(Paths.get(CLASS4_LAMBDA_INTERFACE))
- .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
- .setProguardMapOutputPath(proguardMap)
- .addProguardConfiguration(getProguardConf(), Origin.unknown())
- .build());
-
- Path outputDex = temp.newFolder().toPath().resolve("output");
- Files.createDirectory(outputDex);
- Path splitSpec = createSplitSpec();
-
- DexSplitter.main(
- new String[] {
- "--input", inputDex.toString(),
- "--output", outputDex.toString(),
- "--feature-splits", splitSpec.toString(),
- "--proguard-map", proguardMap.toString()
- });
-
- Path base = outputDex.resolve("base").resolve("classes.dex");
- Path feature = outputDex.resolve("feature1").resolve("classes.dex");
- String class3 = "dexsplitsample.Class3";
- // We should still be able to run the Class3 which we kept, it has a call to the obfuscated
- // class1 which is in base.
- ArtCommandBuilder builder = new ArtCommandBuilder();
- builder.appendClasspath(base.toString());
- builder.appendClasspath(feature.toString());
- builder.setMainClass(class3);
- String out = ToolHelper.runArt(builder);
- assertEquals(out, "Class3\n");
-
- // Class1 should not be in the feature, it should still be in base.
- builder = new ArtCommandBuilder();
- builder.appendClasspath(feature.toString());
- builder.setMainClass(class3);
- try {
- ToolHelper.runArt(builder);
- assertFalse(true);
- } catch (AssertionError assertionError) {
- // We expect this to throw since base is not in the path and Class3 depends on Class1.
- }
-
- // Ensure that the Class1 is actually in the correct split. Note that Class2 would have been
- // shaken away.
- CodeInspector inspector = new CodeInspector(base, proguardMap);
- ClassSubject subject = inspector.clazz("dexsplitsample.Class1");
- assertTrue(subject.isPresent());
- assertTrue(subject.isRenamed());
- }
-
- @Test
- public void splitNonClassFiles()
- throws CompilationFailedException, IOException, FeatureMappingException {
- Path inputZip = temp.getRoot().toPath().resolve("input-zip-with-non-class-files.jar");
- ZipOutputStream inputZipStream = new ZipOutputStream(Files.newOutputStream(inputZip));
- String name = "dexsplitsample/TextFile.txt";
- inputZipStream.putNextEntry(new ZipEntry(name));
- byte[] fileBytes = Files.readAllBytes(Paths.get(TEXT_FILE));
- inputZipStream.write(fileBytes);
- inputZipStream.closeEntry();
- name = "dexsplitsample/TextFile2.txt";
- inputZipStream.putNextEntry(new ZipEntry(name));
- inputZipStream.write(fileBytes);
- inputZipStream.write(fileBytes);
- inputZipStream.closeEntry();
- inputZipStream.close();
- Path output = temp.newFolder().toPath().resolve("output");
- Files.createDirectory(output);
- Path baseJar = temp.getRoot().toPath().resolve("base.jar");
- Path featureJar = temp.getRoot().toPath().resolve("feature1.jar");
- ZipOutputStream baseStream = new ZipOutputStream(Files.newOutputStream(baseJar));
- name = "dexsplitsample/TextFile.txt";
- baseStream.putNextEntry(new ZipEntry(name));
- baseStream.write(fileBytes);
- baseStream.closeEntry();
- baseStream.close();
- ZipOutputStream featureStream = new ZipOutputStream(Files.newOutputStream(featureJar));
- name = "dexsplitsample/TextFile2.txt";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(fileBytes);
- featureStream.write(fileBytes);
- featureStream.closeEntry();
- featureStream.close();
- Options options = new Options();
- options.addInputArchive(inputZip.toString());
- options.setOutput(output.toString());
- options.addFeatureJar(baseJar.toString());
- options.addFeatureJar(featureJar.toString());
- options.setSplitNonClassResources(true);
- DexSplitter.run(options);
- Path baseDir = output.resolve("base");
- Path featureDir = output.resolve("feature1");
- byte[] contents = fileBytes;
- byte[] contents2 = new byte[contents.length * 2];
- System.arraycopy(contents, 0, contents2, 0, contents.length);
- System.arraycopy(contents, 0, contents2, contents.length, contents.length);
- Path baseTextFile = baseDir.resolve("dexsplitsample/TextFile.txt");
- Path featureTextFile = featureDir.resolve("dexsplitsample/TextFile2.txt");
- assert Files.exists(baseTextFile);
- assert Files.exists(featureTextFile);
- assert Arrays.equals(Files.readAllBytes(baseTextFile), contents);
- assert Arrays.equals(Files.readAllBytes(featureTextFile), contents2);
- }
-
- @Test
- public void splitDuplicateNonClassFiles()
- throws IOException, CompilationFailedException, FeatureMappingException {
- Path inputZip = temp.getRoot().toPath().resolve("input-zip-with-non-class-files.jar");
- ZipOutputStream inputZipStream = new ZipOutputStream(Files.newOutputStream(inputZip));
- String name = "dexsplitsample/TextFile.txt";
- inputZipStream.putNextEntry(new ZipEntry(name));
- byte[] fileBytes = Files.readAllBytes(Paths.get(TEXT_FILE));
- inputZipStream.write(fileBytes);
- inputZipStream.closeEntry();
- inputZipStream.close();
- Path output = temp.newFolder().toPath().resolve("output");
- Files.createDirectory(output);
- Path featureJar = temp.getRoot().toPath().resolve("feature1.jar");
- Path feature2Jar = temp.getRoot().toPath().resolve("feature2.jar");
- ZipOutputStream featureStream = new ZipOutputStream(Files.newOutputStream(featureJar));
- name = "dexsplitsample/TextFile.txt";
- featureStream.putNextEntry(new ZipEntry(name));
- featureStream.write(fileBytes);
- featureStream.closeEntry();
- featureStream.close();
- ZipOutputStream feature2Stream = new ZipOutputStream(Files.newOutputStream(feature2Jar));
- name = "dexsplitsample/TextFile.txt";
- feature2Stream.putNextEntry(new ZipEntry(name));
- feature2Stream.write(fileBytes);
- feature2Stream.closeEntry();
- feature2Stream.close();
- Options options = new Options();
- options.addInputArchive(inputZip.toString());
- options.setOutput(output.toString());
- options.addFeatureJar(feature2Jar.toString());
- options.addFeatureJar(featureJar.toString());
- options.setSplitNonClassResources(true);
- DexSplitter.run(options);
- Path baseDir = output.resolve("base");
- Path feature1Dir = output.resolve("feature1");
- Path feature2Dir = output.resolve("feature2");
- Path baseTextFile = baseDir.resolve("dexsplitsample/TextFile.txt");
- Path feature1TextFile = feature1Dir.resolve("dexsplitsample/TextFile2.txt");
- Path feature2TextFile = feature2Dir.resolve("dexsplitsample/TextFile2.txt");
- assert !Files.exists(feature1TextFile);
- assert !Files.exists(feature2TextFile);
- assert Files.exists(baseTextFile);
- assert Arrays.equals(Files.readAllBytes(baseTextFile), fileBytes);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java b/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
index 05d6d3d..bd7929d 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
@@ -17,12 +17,9 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.dexsplitter.DexSplitter.Options;
import com.android.tools.r8.utils.ArchiveResourceProvider;
import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.ThrowingConsumer;
import com.android.tools.r8.utils.ZipUtils;
-import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import dalvik.system.PathClassLoader;
import java.io.IOException;
@@ -31,9 +28,7 @@
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
import java.util.Set;
-import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -155,96 +150,6 @@
toRun, baseOutput, r8TestCompileResult.getFeature(0), parameters.getRuntime());
}
- // Compile the passed in classes plus RunInterface and SplitRunner using R8, then split
- // based on the base/feature sets. toRun must implement the BaseRunInterface
- <E extends Throwable> ProcessResult testDexSplitter(
- TestParameters parameters,
- Set<Class<?>> baseClasses,
- Set<Class<?>> featureClasses,
- Class<?> toRun,
- String expectedOutput,
- ThrowingConsumer<R8TestCompileResult, E> compileResultConsumer,
- Consumer<R8FullTestBuilder> r8TestConfigurator)
- throws Exception, E {
- List<Class<?>> baseClassesWithRunner =
- ImmutableList.<Class<?>>builder()
- .add(RunInterface.class, SplitRunner.class)
- .addAll(baseClasses)
- .build();
-
- Path baseJar = jarTestClasses(baseClassesWithRunner);
- Path featureJar = jarTestClasses(featureClasses);
-
- Path featureOnly =
- testForR8(parameters.getBackend())
- .addProgramClasses(featureClasses)
- .addClasspathClasses(baseClasses)
- .addClasspathClasses(RunInterface.class)
- .addKeepAllClassesRule()
- .addInliningAnnotations()
- .setMinApi(parameters.getApiLevel())
- .compile()
- .writeToZip();
- if (parameters.isDexRuntime()) {
- // With D8 this should just work. We compile all of the base classes, then run with the
- // feature loaded at runtime. Since there is no inlining/class merging we don't
- // have any issues.
- testForD8()
- .addProgramClasses(SplitRunner.class, RunInterface.class)
- .addProgramClasses(baseClasses)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .run(
- parameters.getRuntime(),
- SplitRunner.class,
- toRun.getName(),
- featureOnly.toAbsolutePath().toString())
- .assertSuccessWithOutput(expectedOutput);
- }
-
- R8FullTestBuilder builder = testForR8(parameters.getBackend());
- if (parameters.isCfRuntime()) {
- // Compiling to jar we need to support the same way of loading code at runtime as
- // android supports.
- builder
- .addProgramClasses(PathClassLoader.class)
- .addKeepClassAndMembersRules(PathClassLoader.class);
- }
-
- R8FullTestBuilder r8FullTestBuilder =
- builder
- .setMinApi(parameters.getApiLevel())
- .addProgramClasses(SplitRunner.class, RunInterface.class)
- .addProgramClasses(baseClasses)
- .addProgramClasses(featureClasses)
- .addKeepMainRule(SplitRunner.class)
- .addKeepClassRules(toRun);
- r8TestConfigurator.accept(r8FullTestBuilder);
- R8TestCompileResult r8TestCompileResult = r8FullTestBuilder.compile();
- compileResultConsumer.accept(r8TestCompileResult);
- Path fullFiles = r8TestCompileResult.writeToZip();
-
- // Ensure that we can run the program as a unit (i.e., without splitting)
- r8TestCompileResult
- .run(parameters.getRuntime(), SplitRunner.class, toRun.getName())
- .assertSuccessWithOutput(expectedOutput);
-
- Path splitterOutput = temp.newFolder().toPath();
- Path splitterBaseDexFile = splitterOutput.resolve("base").resolve("classes.dex");
- Path splitterFeatureDexFile = splitterOutput.resolve("feature").resolve("classes.dex");
-
- Options options = new Options();
- options.setOutput(splitterOutput.toString());
- options.addBaseJar(baseJar.toString());
- options.addFeatureJar(featureJar.toString(), "feature");
-
- options.addInputArchive(fullFiles.toString());
- DexSplitter.run(options);
-
- return runFeatureOnArt(
- toRun, splitterBaseDexFile, splitterFeatureDexFile, parameters.getRuntime());
- }
-
ProcessResult runFeatureOnArt(
Class toRun, Path splitterBaseDexFile, Path splitterFeatureDexFile, TestRuntime runtime)
throws IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java b/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java
index 54f2fa4..6aaf325 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeFinalTest.java
@@ -75,8 +75,6 @@
}
public void bar() {
- // TODO(b/110175213): We cannot change this to an invoke-special since this requires a
- // direct bridge in DEX.
foo();
}
}
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index d3e91bb..ced7e4f 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -97,7 +97,7 @@
ProgramMethod method = getMethod(inspector, DEFAULT_CLASS_NAME, "int", "x", ImmutableList.of());
assertFalse(
appInfo
- .resolveMethodOnClassHolder(method.getReference())
+ .resolveMethodOnClassHolderLegacy(method.getReference())
.getSingleTarget()
.isVirtualMethod());
assertNull(appInfo.lookupDirectTarget(method.getReference(), method));
@@ -181,14 +181,15 @@
assertFalse(
appInfo
- .resolveMethodOnClass(classTestSuper, methodXOnTestSuper.getReference())
+ .resolveMethodOnClassLegacy(classTestSuper, methodXOnTestSuper.getReference())
.getSingleTarget()
.isVirtualMethod());
assertNull(
appInfo
- .resolveMethodOnClass(classTest, methodXOnTestSuper.getReference())
+ .resolveMethodOnClassLegacy(classTest, methodXOnTestSuper.getReference())
.getSingleTarget());
- assertNull(appInfo.resolveMethodOnClass(classTest, methodXOnTestReference).getSingleTarget());
+ assertNull(
+ appInfo.resolveMethodOnClassLegacy(classTest, methodXOnTestReference).getSingleTarget());
assertNull(appInfo.lookupDirectTarget(methodXOnTestSuper.getReference(), methodXOnTestSuper));
assertNull(appInfo.lookupDirectTarget(methodXOnTestReference, methodYOnTest));
diff --git a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java
index d05122a..d574d5a 100644
--- a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialOnOtherInterfaceTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,9 +40,14 @@
.addProgramClasses(I.class)
.addProgramClassFileData(getClassWithTransformedInvoked())
.run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatThrowsIf(parameters.isCfRuntime(), VerifyError.class)
// TODO(b/144410139): Consider making this a compilation failure when generating DEX.
- .assertSuccessWithOutputLinesIf(parameters.isDexRuntime(), "Hello World!");
+ .applyIf(
+ parameters.isCfRuntime(),
+ r -> r.assertFailureWithErrorThatThrows(VerifyError.class),
+ !(parameters.isDexRuntimeVersion(Version.V13_0_0)
+ && parameters.canUseDefaultAndStaticInterfaceMethods()),
+ r -> r.assertSuccessWithOutputLines("Hello World!"),
+ r -> r.assertFailureWithErrorThatThrows(NoSuchMethodError.class));
}
@Test
@@ -54,14 +60,17 @@
.enableNoMethodStaticizingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatThrowsIf(parameters.isCfRuntime(), VerifyError.class)
// TODO(b/144410139): Consider making this a compilation failure when generating DEX.
- .assertSuccessWithOutputLinesIf(
+ .applyIf(
+ parameters.isCfRuntime(),
+ r -> r.assertFailureWithErrorThatThrows(VerifyError.class),
parameters.isDexRuntime() && !parameters.canUseDefaultAndStaticInterfaceMethods(),
- "Hello World!")
- .assertFailureWithErrorThatThrowsIf(
- parameters.isDexRuntime() && parameters.canUseDefaultAndStaticInterfaceMethods(),
- NullPointerException.class);
+ r -> r.assertSuccessWithOutputLines("Hello World!"),
+ parameters.isDexRuntime()
+ && !parameters.isDexRuntimeVersion(Version.V13_0_0)
+ && parameters.canUseDefaultAndStaticInterfaceMethods(),
+ r -> r.assertFailureWithErrorThatThrows(NullPointerException.class),
+ r -> r.assertFailureWithErrorThatThrows(NoSuchMethodError.class));
}
private byte[] getClassWithTransformedInvoked() throws IOException {
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
index 956d59e..b8078ae 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -72,11 +72,12 @@
// Check lookup will produce the same result.
DexMethod id = method.getReference();
assertEquals(
- appInfo().resolveMethodOnClass(id.holder, method.getReference()).getSingleTarget(), method);
+ appInfo().resolveMethodOnClassLegacy(id.holder, method.getReference()).getSingleTarget(),
+ method);
// Check lookup targets with include method.
MethodResolutionResult resolutionResult =
- appInfo().resolveMethodOnClass(clazz, method.getReference());
+ appInfo().resolveMethodOnClassLegacy(clazz, method.getReference());
AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness.
LookupResult lookupResult =
resolutionResult.lookupVirtualDispatchTargets(
@@ -97,7 +98,7 @@
AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness.
LookupResultSuccess lookupResult =
appInfo()
- .resolveMethodOnInterface(clazz, method.getReference())
+ .resolveMethodOnInterfaceLegacy(clazz, method.getReference())
.lookupVirtualDispatchTargets(clazz, appInfo(), appInfo, dexReference -> false)
.asLookupResultSuccess();
assertNotNull(lookupResult);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
index a729899..68c055d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
@@ -99,7 +99,7 @@
}
if (parameters.isDexRuntime()) {
if (parameters.getDexRuntimeVersion().isEqualTo(Version.V7_0_0)
- || parameters.getDexRuntimeVersion().isEqualTo(Version.V13_MASTER)) {
+ || parameters.getDexRuntimeVersion().isEqualTo(Version.V13_0_0)) {
return ImmutableList.of("true");
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java
index 6bbfb60..dc3ca19 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java
@@ -33,7 +33,6 @@
.setMinApi(parameters.getApiLevel())
.addProgramClasses(Main.class)
.addKeepMainRule(Main.class)
- .addOptionsModification(options -> options.testing.enableExperimentalLoopUnrolling = true)
.enableInliningAnnotations()
.noMinification()
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1IterationsEscape.java b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1IterationsEscape.java
new file mode 100644
index 0000000..07efa85
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1IterationsEscape.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.loops;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class LoopWith1IterationsEscape extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public LoopWith1IterationsEscape(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testLoopRemoved() throws Exception {
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(Main.class)
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ .noMinification()
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("end 0", "iteration", "end 1");
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ loopExit();
+ loopNoExit();
+ }
+
+ @NeverInline
+ public static void loopNoExit() {
+ Object[] objects = new Object[1];
+ int i;
+ for (i = 0; i < objects.length; i++) {
+ if (System.currentTimeMillis() < 0) {
+ break;
+ }
+ System.out.println("iteration");
+ }
+ System.out.println("end " + i);
+ }
+
+ @NeverInline
+ public static void loopExit() {
+ Object[] objects = new Object[1];
+ int i;
+ for (i = 0; i < objects.length; i++) {
+ if (System.currentTimeMillis() > 0) {
+ break;
+ }
+ System.out.println("iteration");
+ }
+ System.out.println("end " + i);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantInstanceStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantInstanceStoreTest.java
index 4c3f07d..29ab7c9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantInstanceStoreTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantInstanceStoreTest.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,7 +37,11 @@
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("1");
+ .applyIf(
+ // See b/229706824.
+ parameters.getDexRuntimeVersion().equals(Version.V13_0_0),
+ r -> r.assertSuccessWithOutputLines("0"),
+ r -> r.assertSuccessWithOutputLines("1"));
}
static class Main {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantStaticStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantStaticStoreTest.java
index 60a0b34..abf3664 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantStaticStoreTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/ThrowingInstructionBeforeOtherwiseRedundantStaticStoreTest.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,7 +37,11 @@
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("1");
+ .applyIf(
+ // See b/229706824.
+ parameters.getDexRuntimeVersion().equals(Version.V13_0_0),
+ r -> r.assertSuccessWithOutputLines("0"),
+ r -> r.assertSuccessWithOutputLines("1"));
}
static class Main {
diff --git a/src/test/java/com/android/tools/r8/jasmin/Regress65007724.java b/src/test/java/com/android/tools/r8/jasmin/Regress65007724.java
index cdc5b63..90660f4 100644
--- a/src/test/java/com/android/tools/r8/jasmin/Regress65007724.java
+++ b/src/test/java/com/android/tools/r8/jasmin/Regress65007724.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -51,11 +50,6 @@
.setMinApi(parameters.getApiLevel())
.addProgramClassFileData(builder.buildClasses())
.run(parameters.getRuntime(), clazz.name);
- if (parameters.getDexRuntimeVersion().isEqualTo(Version.V13_MASTER)) {
- // See b/220821265
- d8TestRunResult.assertFailure();
- } else {
- d8TestRunResult.assertSuccessWithOutput("Hello World!");
- }
+ d8TestRunResult.assertSuccessWithOutput("Hello World!");
}
}
diff --git a/src/test/java/com/android/tools/r8/lightir/LIRBasicCallbackTest.java b/src/test/java/com/android/tools/r8/lightir/LIRBasicCallbackTest.java
new file mode 100644
index 0000000..0602eb3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/lightir/LIRBasicCallbackTest.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.lightir;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.IntBox;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class LIRBasicCallbackTest extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public LIRBasicCallbackTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ @Test
+ public void test() throws Exception {
+ LIRCode code = LIRCode.builder().addConstNull().addConstInt(42).build();
+
+ // State to keep track of position in the byte array as we don't expose this in the iterator.
+ IntBox offset = new IntBox(0);
+
+ LIRIterator it = code.iterator();
+
+ // The iterator and the elements are the same object providing a view on the byte stream.
+ assertTrue(it.hasNext());
+ LIRInstructionView next = it.next();
+ assertSame(it, next);
+
+ it.accept(
+ (int opcode, int operandOffset, int operandSize) -> {
+ int headerSize = 1;
+ assertEquals(LIROpcodes.ACONST_NULL, opcode);
+ assertEquals(offset.get() + headerSize, operandOffset);
+ assertEquals(0, operandSize);
+ offset.increment(headerSize + operandSize);
+ });
+
+ assertTrue(it.hasNext());
+ it.next();
+ it.accept(
+ (int opcode, int operandOffset, int operandSize) -> {
+ int headerSize = 2; // opcode + payload-size
+ assertEquals(LIROpcodes.ICONST, opcode);
+ assertEquals(offset.get() + headerSize, operandOffset);
+ assertEquals(4, operandSize);
+ offset.increment(headerSize + operandSize);
+ });
+ assertFalse(it.hasNext());
+
+ // The iterator can also be use in a normal java for-each loop.
+ // However, the item is not an actual item just a current view, so it can't be cached!
+ LIRInstructionView oldView = null;
+ for (LIRInstructionView view : code) {
+ if (oldView == null) {
+ oldView = view;
+ view.accept((opcode, ignore1, ignore2) -> assertEquals(LIROpcodes.ACONST_NULL, opcode));
+ } else {
+ assertSame(oldView, view);
+ view.accept((opcode, ignore1, ignore2) -> assertEquals(LIROpcodes.ICONST, opcode));
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index dd40ecf..75b7dda 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -25,8 +25,6 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.dexsplitter.DexSplitter;
-import com.android.tools.r8.dexsplitter.DexSplitter.Options;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
import com.android.tools.r8.errors.Unreachable;
@@ -255,49 +253,6 @@
}
@Test
- public void everyThirdClassInMainWithDexSplitter() throws Throwable {
- List<String> featureMappings = new ArrayList<>();
- List<String> inFeatureMapping = new ArrayList<>();
-
- ImmutableList.Builder<String> mainDexBuilder = ImmutableList.builder();
- for (int i = 0; i < MANY_CLASSES.size(); i++) {
- String clazz = MANY_CLASSES.get(i);
- // Write the first 2 classes into the split.
- if (i < 10) {
- featureMappings.add(clazz + ":feature1");
- inFeatureMapping.add(clazz);
- }
- if (i % 3 == 0) {
- mainDexBuilder.add(clazz);
- }
- }
- Path featureSplitMapping = temp.getRoot().toPath().resolve("splitmapping");
- Path mainDexFile = temp.getRoot().toPath().resolve("maindex");
- FileUtils.writeTextFile(featureSplitMapping, featureMappings);
- List<String> mainDexList = mainDexBuilder.build();
- FileUtils.writeTextFile(mainDexFile, ListUtils.map(mainDexList, MainDexListTests::typeToEntry));
- Path output = temp.getRoot().toPath().resolve("split_output");
- Files.createDirectories(output);
- TestDiagnosticsHandler diagnosticsHandler = new TestDiagnosticsHandler();
- Options options = new Options(diagnosticsHandler);
- options.addInputArchive(getManyClassesMultiDexAppPath().toString());
- options.setFeatureSplitMapping(featureSplitMapping.toString());
- options.setOutput(output.toString());
- options.setMainDexList(mainDexFile.toString());
- DexSplitter.run(options);
- assertEquals(0, diagnosticsHandler.numberOfErrorsAndWarnings());
- Path baseDir = output.resolve("base");
- CodeInspector inspector =
- new CodeInspector(
- AndroidApp.builder().addProgramFiles(baseDir.resolve("classes.dex")).build());
- for (String clazz : mainDexList) {
- if (!inspector.clazz(clazz).isPresent() && !inFeatureMapping.contains(clazz)) {
- failedToFindClassInExpectedFile(baseDir, clazz);
- }
- }
- }
-
- @Test
public void singleClassInMainDex() throws Throwable {
ImmutableList<String> mainDex = ImmutableList.of(MANY_CLASSES.get(0));
verifyMainDexContains(mainDex, getManyClassesSingleDexAppPath(), true);
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest.java
new file mode 100644
index 0000000..836c703
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest.java
@@ -0,0 +1,74 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.argumentpropagation;
+
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import 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 InterfaceInvokeWithNonTrivialButImpreciseStaticTypeTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .enableNoHorizontalClassMergingAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("B");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ I i = System.currentTimeMillis() > 0 ? new B() : new C();
+ i.m();
+ }
+ }
+
+ @NoVerticalClassMerging
+ interface I {
+
+ void m();
+ }
+
+ static class A {}
+
+ @NoHorizontalClassMerging
+ static class B extends A implements I {
+
+ @Override
+ public void m() {
+ System.out.println("B");
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class C extends A implements I {
+
+ @Override
+ public void m() {
+ System.out.println("C");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
index 7ea76aa..5b061d7 100644
--- a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
@@ -50,18 +50,18 @@
};
DexEncodedMethod langObjectNotifyMethod =
appInfo
- .resolveMethodOnClassHolder(
+ .resolveMethodOnClassHolderLegacy(
factory.createMethod(fooType, factory.createProto(factory.voidType), "notify"))
.getSingleTarget();
for (DexType arrType : arrayTypes) {
assertNull(
appInfo
- .resolveMethodOnClassHolder(
+ .resolveMethodOnClassHolderLegacy(
factory.createMethod(arrType, factory.createProto(arrType), "clone"))
.getSingleTarget());
DexEncodedMethod target =
appInfo
- .resolveMethodOnClassHolder(
+ .resolveMethodOnClassHolderLegacy(
factory.createMethod(arrType, factory.createProto(factory.voidType), "notify"))
.getSingleTarget();
assertEquals(langObjectNotifyMethod, target);
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokePolymorphicResolutionTest.java b/src/test/java/com/android/tools/r8/resolution/InvokePolymorphicResolutionTest.java
index 1b0af62..db280ea 100644
--- a/src/test/java/com/android/tools/r8/resolution/InvokePolymorphicResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/InvokePolymorphicResolutionTest.java
@@ -48,7 +48,9 @@
MethodReference invokeExact =
methodFromMethod(MethodHandle.class.getMethod("invokeExact", Object[].class));
MethodResolutionResult resolution1 =
- appView.appInfo().resolveMethod(buildMethod(invokeExact, appView.dexItemFactory()), false);
+ appView
+ .appInfo()
+ .resolveMethodLegacy(buildMethod(invokeExact, appView.dexItemFactory()), false);
assertFalse(resolution1.isFailedResolution());
// An inexact signature should also find invokeExact.
@@ -61,7 +63,7 @@
MethodResolutionResult resolution2 =
appView
.appInfo()
- .resolveMethod(buildMethod(inexactInvokeExact, appView.dexItemFactory()), false);
+ .resolveMethodLegacy(buildMethod(inexactInvokeExact, appView.dexItemFactory()), false);
assertFalse(resolution2.isFailedResolution());
// The should both be the same MethodHandle.invokeExact method.
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
index 67007d2c..ebee166 100644
--- a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
@@ -59,7 +59,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Base.class, "collect", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
assertTrue(resolutionResult.isSingleResolution());
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index 76cf55a..4c668d0 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -194,7 +194,7 @@
buildNullaryVoidMethod(invokeReceiver, methodName, appInfo.dexItemFactory());
ProgramMethod context =
appInfo.definitionForProgramType(reference.holder).getProgramDefaultInitializer();
- Assert.assertNotNull(appInfo.resolveMethodOnClassHolder(reference).getSingleTarget());
+ Assert.assertNotNull(appInfo.resolveMethodOnClassHolderLegacy(reference).getSingleTarget());
DexEncodedMethod singleVirtualTarget =
appInfo.lookupSingleVirtualTarget(appView, reference, context, false);
if (singleTargetHolderOrNull == null) {
@@ -209,8 +209,8 @@
@Test
public void lookupVirtualTargets() {
DexMethod method = buildNullaryVoidMethod(invokeReceiver, methodName, appInfo.dexItemFactory());
- Assert.assertNotNull(appInfo.resolveMethodOnClassHolder(method).getSingleTarget());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ Assert.assertNotNull(appInfo.resolveMethodOnClassHolderLegacy(method).getSingleTarget());
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
if (resolutionResult.isVirtualTarget()) {
LookupResult lookupResult =
resolutionResult.lookupVirtualDispatchTargets(
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
index 9de13d2..4fbc7e7 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
@@ -91,7 +91,7 @@
@Test
public void resolveTarget() {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
+ appInfo.resolveMethodOnClassLegacy(methodOnB.holder, methodOnB);
DexClass context = appInfo.definitionFor(methodOnB.holder);
assertTrue(resolutionResult.isIllegalAccessErrorResult(context, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
index d8ad8dd..77f847c 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
@@ -108,7 +108,7 @@
@Test
public void testResolution() {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
+ appInfo.resolveMethodOnClassLegacy(methodOnB.holder, methodOnB);
assertTrue(resolutionResult.isFailedResolution());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
index ca541ea..8118ef2 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
@@ -128,7 +128,7 @@
DexProgramClass bClass = appInfo.definitionForProgramType(methodOnBReference.holder);
ProgramMethod methodOnB = bClass.lookupProgramMethod(methodOnBReference);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(methodOnBReference.holder, methodOnBReference);
+ appInfo.resolveMethodOnInterfaceLegacy(methodOnBReference.holder, methodOnBReference);
DexEncodedMethod resolved = resolutionResult.getSingleTarget();
assertEquals(methodOnBReference, resolved.getReference());
assertFalse(resolutionResult.isVirtualTarget());
@@ -140,7 +140,7 @@
@Test
public void lookupVirtualTargets() {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(methodOnBReference.holder, methodOnBReference);
+ appInfo.resolveMethodOnInterfaceLegacy(methodOnBReference.holder, methodOnBReference);
DexEncodedMethod resolved = resolutionResult.getSingleTarget();
assertEquals(methodOnBReference, resolved.getReference());
assertFalse(resolutionResult.isVirtualTarget());
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
index c40f080..47c0857 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
@@ -175,7 +175,7 @@
public void lookupSingleTarget() {
DexProgramClass bClass = appView.definitionForProgramType(methodOnB.holder);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
+ appInfo.resolveMethodOnClassLegacy(methodOnB.holder, methodOnB);
DexEncodedMethod resolved = resolutionResult.getSingleTarget();
assertEquals(methodOnA, resolved.getReference());
assertFalse(resolutionResult.isVirtualTarget());
@@ -188,7 +188,7 @@
@Test
public void lookupVirtualTargets() {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
+ appInfo.resolveMethodOnClassLegacy(methodOnB.holder, methodOnB);
DexEncodedMethod resolved = resolutionResult.getSingleTarget();
assertEquals(methodOnA, resolved.getReference());
assertFalse(resolutionResult.isVirtualTarget());
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
index 898cfae..aa827c8 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -122,7 +122,7 @@
// Resolve the method from the point of the declared holder.
assertEquals(method.holder, declaredClassDefinition.type);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOn(declaredClassDefinition, method);
+ appInfo.resolveMethodOnLegacy(declaredClassDefinition, method);
if (!symbolicReferenceIsDefiningType) {
// The targeted method is a private interface method and thus not a maximally specific method.
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
index 82c6b63..50f4428 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
@@ -123,7 +123,7 @@
// Resolve the method from the point of the declared holder.
assertEquals(method.holder, declaredClassDefinition.type);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOn(declaredClassDefinition, method);
+ appInfo.resolveMethodOnLegacy(declaredClassDefinition, method);
// The targeted method is a private interface method and thus not a maximally specific method.
assertTrue(resolutionResult instanceof NoSuchMethodResult);
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
index b14ab55..1a6485c 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
@@ -96,7 +96,7 @@
// Resolve the method from the point of the declared holder.
assertEquals(method.holder, declaredClassDefinition.type);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOn(declaredClassDefinition, method);
+ appInfo.resolveMethodOnLegacy(declaredClassDefinition, method);
// Verify that the resolved method is on the defining class.
assertEquals(
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
index 5638929..5fddce3 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -121,7 +121,7 @@
// Resolve the method from the point of the declared holder.
assertEquals(method.holder, declaredClassDefinition.type);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOn(declaredClassDefinition, method);
+ appInfo.resolveMethodOnLegacy(declaredClassDefinition, method);
// Resolution fails when there is a mismatch between the symbolic reference and the definition.
if (!symbolicReferenceIsDefiningType) {
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
index d65dabf..31a8904 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
@@ -98,7 +98,7 @@
// Resolve the method from the point of the declared holder.
assertEquals(method.holder, declaredClassDefinition.type);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOn(declaredClassDefinition, method);
+ appInfo.resolveMethodOnLegacy(declaredClassDefinition, method);
// Verify that the resolved method is on the defining class.
assertEquals(
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
index f1a35bb..63cd43e 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
@@ -74,7 +74,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
index d68610e..f7bfe55 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
@@ -73,7 +73,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
index ccc0430..7d9eb16 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
@@ -76,7 +76,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
index f2f7dd9..4a9c475 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
@@ -72,7 +72,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
index a91d3ed..754b19d 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
@@ -59,7 +59,7 @@
DexProgramClass aClass =
appInfo.definitionFor(buildType(A.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(bar);
assertEquals(OptionalBool.TRUE, resolutionResult.isAccessibleFrom(aClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
index 9ae877d..c5363de 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
@@ -65,7 +65,7 @@
DexProgramClass cClass =
appInfo.definitionFor(buildType(C.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(B.class.getMethod("foo"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(bar);
assertEquals(
OptionalBool.TRUE, resolutionResult.isAccessibleForVirtualDispatchFrom(cClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificDifferentParentHierarchyTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificDifferentParentHierarchyTest.java
new file mode 100644
index 0000000..856d3fe
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificDifferentParentHierarchyTest.java
@@ -0,0 +1,153 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { f }
+ * J: J_L extends I { }, J_P { f }
+ * class Main implements I, J
+ * </pre>
+ */
+public class MaximallySpecificDifferentParentHierarchyTest extends TestBase {
+
+ private static final String EXPECTED = "I::foo";
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(I.class),
+ ToolHelper.getClassFileForTestClass(J.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder
+ .addProgramFiles(ToolHelper.getClassFileForTestClass(Main.class))
+ .addClassProgramData(getJProgram());
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getJProgram())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ runTest(testForD8(parameters.getBackend()))
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ .assertFailureWithErrorThatThrowsIf(
+ !parameters.canUseDefaultAndStaticInterfaceMethods(),
+ IncompatibleClassChangeError.class)
+ .assertSuccessWithOutputLinesIf(
+ parameters.canUseDefaultAndStaticInterfaceMethods(), EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+ .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
+ }
+
+ private TestRunResult<?> runTest(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
+ throws Exception {
+ return testBuilder
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getJProgram())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class);
+ }
+
+ private byte[] getJProgram() throws Exception {
+ return transformer(JProgram.class).setClassDescriptor(descriptor(J.class)).transform();
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public interface JProgram {
+ default void foo() {
+ System.out.println("J_Program::foo");
+ }
+ }
+
+ public interface J extends I {}
+
+ public static class Main implements I, J {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsICCETest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsICCETest.java
new file mode 100644
index 0000000..2e57f9f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsICCETest.java
@@ -0,0 +1,146 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { f }, I_P { f }
+ * J: J_L { f }, J_P { f }
+ * class Main implements I,J
+ * </pre>
+ */
+public class MaximallySpecificMultiplePathsICCETest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(J.class),
+ ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder
+ .addProgramFiles(
+ ToolHelper.getClassFileForTestClass(I.class),
+ ToolHelper.getClassFileForTestClass(J.class))
+ .addClassProgramData(getMainWithInterfacesIAndJ());
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClasses(I.class, J.class)
+ .addProgramClassFileData(getMainWithInterfacesIAndJ())
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ runTest(testForD8(parameters.getBackend()), IncompatibleClassChangeError.class);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTest(
+ testForR8(parameters.getBackend()).addKeepMainRule(Main.class),
+ IncompatibleClassChangeError.class);
+ }
+
+ private void runTest(
+ TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, Class<? extends Throwable> errorClass)
+ throws Exception {
+ testBuilder
+ .addProgramClasses(I.class, J.class)
+ .addProgramClassFileData(getMainWithInterfacesIAndJ())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(errorClass);
+ }
+
+ private byte[] getMainWithInterfacesIAndJ() throws Exception {
+ return transformer(Main.class).setImplements(I.class, J.class).transform();
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public interface J {
+ default void foo() {
+ System.out.println("J::foo");
+ }
+ }
+
+ public static class Main implements I /*, J */ {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
new file mode 100644
index 0000000..c743ac4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
@@ -0,0 +1,167 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { f }, I_P { }
+ * J: J_L { }, J_P { f }
+ * class Main implements I,J
+ * </pre>
+ */
+public class MaximallySpecificMultiplePathsSuccessTest extends TestBase {
+
+ private static final String EXPECTED = "I::foo";
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ private static final String D8_R8_RESULT = "J::foo";
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(J.class),
+ ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder
+ .addProgramFiles(ToolHelper.getClassFileForTestClass(Main.class))
+ .addClassProgramData(getIProgram())
+ .addClassProgramData(getJProgram());
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getIProgram(), getJProgram())
+ .addDefaultRuntimeLibrary(parameters)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ boolean isDalvik = parameters.getDexRuntimeVersion().isDalvik();
+ runTest(testForD8(parameters.getBackend()))
+ .assertSuccessWithOutputLinesIf(isDalvik, D8_R8_RESULT)
+ .assertSuccessWithOutputLinesIf(
+ !isDalvik && !parameters.canUseDefaultAndStaticInterfaceMethods(), D8_R8_RESULT)
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ .assertSuccessWithOutputLinesIf(
+ parameters.canUseDefaultAndStaticInterfaceMethods(), EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+ .assertFailureWithErrorThatThrowsIf(
+ parameters.canUseDefaultAndStaticInterfaceMethods(), NoSuchMethodError.class)
+ .assertSuccessWithOutputLinesIf(
+ !parameters.canUseDefaultAndStaticInterfaceMethods(), D8_R8_RESULT);
+ }
+
+ private TestRunResult<?> runTest(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
+ throws Exception {
+ return testBuilder
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getIProgram(), getJProgram())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class);
+ }
+
+ private byte[] getJProgram() throws Exception {
+ return transformer(JProgram.class).setClassDescriptor(descriptor(J.class)).transform();
+ }
+
+ private byte[] getIProgram() throws Exception {
+ return transformer(IProgram.class).setClassDescriptor(descriptor(I.class)).transform();
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public interface J {}
+
+ public interface IProgram {}
+
+ public interface JProgram {
+ default void foo() {
+ System.out.println("J::foo");
+ }
+ }
+
+ public static class Main implements I, J {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsThroughClassTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsThroughClassTest.java
new file mode 100644
index 0000000..a14d33a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsThroughClassTest.java
@@ -0,0 +1,158 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { f }, I_P { f }
+ * A: A_P implements I { }
+ * J: J_P { f }
+ * class Main extends A implements J
+ * </pre>
+ */
+public class MaximallySpecificMultiplePathsThroughClassTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder
+ .addProgramFiles(
+ ToolHelper.getClassFileForTestClass(Main.class),
+ ToolHelper.getClassFileForTestClass(J.class))
+ .addClassProgramData(getAWithImplementsI())
+ .addClassProgramData(getIProgram());
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClasses(J.class, Main.class)
+ .addProgramClassFileData(getAWithImplementsI(), getIProgram())
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ runTest(testForD8(parameters.getBackend()), IncompatibleClassChangeError.class);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTest(
+ testForR8(parameters.getBackend()).addKeepMainRule(Main.class),
+ IncompatibleClassChangeError.class);
+ }
+
+ private void runTest(
+ TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, Class<? extends Throwable> errorClass)
+ throws Exception {
+ testBuilder
+ .addProgramClasses(J.class, Main.class)
+ .addProgramClassFileData(getAWithImplementsI(), getIProgram())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(errorClass);
+ }
+
+ private byte[] getAWithImplementsI() throws Exception {
+ return transformer(A.class).setImplements(I.class).transform();
+ }
+
+ private byte[] getIProgram() throws Exception {
+ return transformer(IProgram.class).setClassDescriptor(descriptor(I.class)).transform();
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public interface IProgram {
+ default void foo() {
+ System.out.println("I_Program::foo");
+ }
+ }
+
+ public interface J {
+ default void foo() {
+ System.out.println("J::foo");
+ }
+ }
+
+ public static class A /* implements I */ {}
+
+ public static class Main extends A implements J {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingAfterJoinTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingAfterJoinTest.java
new file mode 100644
index 0000000..3e3b85b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingAfterJoinTest.java
@@ -0,0 +1,156 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { f }
+ * J: J_L extends I { f }
+ * K: K_L extends J { }, K_P extends J { }
+ * class Main implements I,K
+ * </pre>
+ */
+public class MaximallySpecificSingleDominatingAfterJoinTest extends TestBase {
+
+ private static final String EXPECTED = "J::foo";
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(K.class),
+ ToolHelper.getClassFileForTestClass(J.class),
+ ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder.addProgramFiles(
+ ToolHelper.getClassFileForTestClass(K.class),
+ ToolHelper.getClassFileForTestClass(Main.class));
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClasses(K.class, Main.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ runTest(
+ testForD8(parameters.getBackend()),
+ parameters.getDexRuntimeVersion().isDalvik()
+ ? VerifyError.class
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ : AbstractMethodError.class);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTest(
+ testForR8(parameters.getBackend()).addKeepMainRule(Main.class), AbstractMethodError.class);
+ }
+
+ private void runTest(
+ TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder,
+ Class<? extends Throwable> errorIfNotSupportingDefaultMethods)
+ throws Exception {
+ testBuilder
+ .addProgramClasses(K.class, Main.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLinesIf(
+ parameters.canUseDefaultAndStaticInterfaceMethods(), EXPECTED)
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ .assertFailureWithErrorThatThrowsIf(
+ !parameters.canUseDefaultAndStaticInterfaceMethods(),
+ errorIfNotSupportingDefaultMethods);
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public interface J extends I {
+ @Override
+ default void foo() {
+ System.out.println("J::foo");
+ }
+ }
+
+ /* Present on both library and program */
+ public interface K extends J {}
+
+ public static class Main implements I, K {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingSubTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingSubTest.java
new file mode 100644
index 0000000..630c284
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingSubTest.java
@@ -0,0 +1,165 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { f }
+ * J: J_L extends I { f }, J_P extends I { f }
+ * K: K_P extends J { f }
+ * class Main implements I,K
+ * </pre>
+ */
+public class MaximallySpecificSingleDominatingSubTest extends TestBase {
+
+ private static final String EXPECTED = "K::foo";
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(J.class),
+ ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder
+ .addProgramFiles(
+ ToolHelper.getClassFileForTestClass(K.class),
+ ToolHelper.getClassFileForTestClass(Main.class))
+ .addClassProgramData(ImmutableList.of(getJOnProgram()));
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClasses(K.class, Main.class)
+ .addProgramClassFileData(getJOnProgram())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ runTest(testForD8(parameters.getBackend()));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class));
+ }
+
+ private void runTest(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception {
+ testBuilder
+ .addProgramClasses(K.class, Main.class)
+ .addProgramClassFileData(getJOnProgram())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ private byte[] getJOnProgram() throws Exception {
+ return transformer(JProgram.class).setClassDescriptor(descriptor(J.class)).transform();
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ /* Present on both library and program */
+ public interface JProgram extends I {
+ @Override
+ default void foo() {
+ System.out.println("J_Program::foo");
+ ;
+ }
+ }
+
+ public interface J extends I {
+ @Override
+ default void foo() {
+ System.out.println("J_Library::foo");
+ ;
+ }
+ }
+
+ public interface K extends J {
+
+ @Override
+ default void foo() {
+ System.out.println("K::foo");
+ }
+ }
+
+ public static class Main implements I, K {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleLibraryPartialTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleLibraryPartialTest.java
new file mode 100644
index 0000000..c840cc2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleLibraryPartialTest.java
@@ -0,0 +1,146 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { f }, I_P { }
+ * class Main implements I
+ * </pre>
+ */
+public class MaximallySpecificSingleLibraryPartialTest extends TestBase {
+
+ private static final String EXPECTED = "I::foo";
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder
+ .addProgramFiles(ToolHelper.getClassFileForTestClass(Main.class))
+ .addClassProgramData(getIProgram());
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getIProgram())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ runTest(testForD8(parameters.getBackend()))
+ .assertFailureWithErrorThatThrowsIf(
+ !parameters.canUseDefaultAndStaticInterfaceMethods(),
+ parameters.getDexRuntimeVersion().isDalvik()
+ ? VerifyError.class
+ : AbstractMethodError.class)
+ .assertSuccessWithOutputLinesIf(
+ parameters.canUseDefaultAndStaticInterfaceMethods(), EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+ .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+ }
+
+ private TestRunResult<?> runTest(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
+ throws Exception {
+ return testBuilder
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(getIProgram())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class);
+ }
+
+ private byte[] getIProgram() throws Exception {
+ return transformer(IProgram.class).setClassDescriptor(descriptor(I.class)).transform();
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public interface IProgram {}
+
+ public static class Main implements I {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
new file mode 100644
index 0000000..de9876c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
@@ -0,0 +1,146 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+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)
+/**
+ * This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { }, I_P { f }
+ * class Main implements I
+ * </pre>
+ */
+public class MaximallySpecificSingleProgramPartialTest extends TestBase {
+
+ private static final String UNEXPECTED = "I::foo";
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private Path libraryClasses;
+
+ @Before
+ public void setup() throws Exception {
+ libraryClasses = temp.newFile("lib.jar").toPath();
+ ZipBuilder.builder(libraryClasses)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ }
+
+ @Test
+ public void testResolution() throws Exception {
+ assumeTrue(parameters.useRuntimeAsNoneRuntime());
+ AndroidApp.Builder builder = AndroidApp.builder();
+ builder.addClassProgramData(getMainImplementingI()).addClassProgramData(getIProgram());
+ builder.addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses);
+ AppView<AppInfoWithClassHierarchy> appView =
+ computeAppViewWithClassHierarchy(
+ builder.build(), null, options -> options.loadAllClassDefinitions = true);
+ AppInfoWithClassHierarchy appInfo = appView.appInfo();
+ DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ assertThrows(
+ Unreachable.class,
+ () -> {
+ appInfo.unsafeResolveMethodDueToDexFormat(method);
+ });
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(libraryClasses)
+ .addProgramClassFileData(getMainImplementingI(), getIProgram())
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ runTest(testForD8(parameters.getBackend()))
+ .assertFailureWithErrorThatThrowsIf(
+ parameters.canUseDefaultAndStaticInterfaceMethods(), NoSuchMethodError.class)
+ .assertSuccessWithOutputLinesIf(
+ !parameters.canUseDefaultAndStaticInterfaceMethods(), UNEXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // TODO(b/214382176): Extend resolution to support multiple definition results.
+ runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+ .assertFailureWithErrorThatThrowsIf(
+ parameters.canUseDefaultAndStaticInterfaceMethods(), NoSuchMethodError.class)
+ .assertSuccessWithOutputLinesIf(
+ !parameters.canUseDefaultAndStaticInterfaceMethods(), UNEXPECTED);
+ }
+
+ private TestRunResult<?> runTest(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
+ throws Exception {
+ return testBuilder
+ .addProgramClassFileData(getMainImplementingI(), getIProgram())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(libraryClasses)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.loadAllClassDefinitions = true)
+ .compile()
+ .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+ .run(parameters.getRuntime(), Main.class);
+ }
+
+ private byte[] getIProgram() throws Exception {
+ return transformer(IProgram.class).setClassDescriptor(descriptor(I.class)).transform();
+ }
+
+ private byte[] getMainImplementingI() throws Exception {
+ return transformer(Main.class).setImplements(I.class).transform();
+ }
+
+ public interface I {}
+
+ public interface IProgram {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public static class Main implements /* I */ IProgram {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
index 81a0f45..51f29aa 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
@@ -45,7 +45,7 @@
buildClasses(CLASSES).addLibraryFile(parameters.getDefaultRuntimeLibrary()).build();
AppInfoWithLiveness appInfo = computeAppViewWithLiveness(app, Main.class).appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
// Currently R8 will resolve to L::f as that is the first in the topological search.
// Resolution may return any of the matches, so it is valid if this expectation changes.
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
index d708d1e..05bb852 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
@@ -51,7 +51,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(L.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
index 8f94ef3..7314ee5 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
@@ -51,7 +51,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(R.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
index 6b31505..9f1df3e 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
@@ -53,7 +53,7 @@
Main.class)
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(L.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
index 0b78a07..b5cac2e 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
@@ -53,7 +53,7 @@
Main.class)
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(R.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
index 7f09e71..31e9e9e 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
@@ -53,7 +53,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
Set<String> holders = new HashSet<>();
resolutionResult
.asFailedResolution()
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
index 0f37198..53a17c4 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
@@ -50,7 +50,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(L.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
index 8d35771..018cddb 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
@@ -50,7 +50,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(R.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
index 290dbec..d5aefd7 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
@@ -58,7 +58,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
if (minApi.isLessThan(apiLevelWithDefaultInterfaceMethodsSupport())) {
// When desugaring a forwarding method throwing ICCE is inserted.
// Check that the resolved method throws such an exception.
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
index b3c88c7..e838d5d 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
@@ -64,7 +64,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
index 1b3d3d9..dfa7451 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
@@ -63,7 +63,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
index 8908dce..ed99f3e 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
@@ -112,7 +112,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
index 8122941..9002d8d 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
index ca5e24e..29ae548 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
@@ -56,7 +56,7 @@
AssertionError.class,
() ->
appInfo
- .resolveMethodOnInterfaceHolder(method)
+ .resolveMethodOnInterfaceHolderLegacy(method)
.lookupVirtualDispatchTargets(context, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
index 0819b97..6d93202 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
@@ -63,7 +63,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(J.class, "bar", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
index 5912e69..8b1b588 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
@@ -61,7 +61,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
index 3503bdf..c48764d 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
@@ -61,7 +61,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
index 4d85bfb..50e000b 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
@@ -63,7 +63,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
index 682d447..a3b1d8f 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
@@ -60,7 +60,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
index bbf73d7..1d8a03a 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
@@ -60,7 +60,7 @@
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnInterface(method.holder, method);
+ appInfo.resolveMethodOnInterfaceLegacy(method.holder, method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
index bff70ca..13a108d 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
@@ -74,7 +74,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Abstract.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Abstract.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
index 255fbed..45eab24 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
@@ -59,7 +59,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
index f33ee0b..a875b43 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
@@ -63,7 +63,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
@@ -86,7 +86,8 @@
.addProgramClassFileData(getDWithPackagePrivateFoo())
.run(parameters.getRuntime(), Main.class);
if (parameters.isCfRuntime()
- || parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_TARGET)) {
+ || parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_TARGET)
+ || parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_13_0_0_TARGET)) {
runResult.assertSuccessWithOutputLines(EXPECTED);
} else {
runResult.assertSuccessWithOutputLines(EXPECTED_ART);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
index be8acd3..3eb13d5 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
@@ -73,7 +73,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
index 8846bf2..6ccf173 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
@@ -67,7 +67,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
assertTrue(resolutionResult.isAccessibleFrom(context, appView).isFalse());
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
index da660f2..7a588f3 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
@@ -60,7 +60,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
index 58c64b1..42733a1 100644
--- a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
@@ -131,7 +131,7 @@
DexMethod fooA = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
DexMethod fooB = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory());
DexMethod fooC = buildNullaryVoidMethod(C.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolution = appInfo.resolveMethodOnClassHolder(fooA);
+ MethodResolutionResult resolution = appInfo.resolveMethodOnClassHolderLegacy(fooA);
DexProgramClass context = appView.definitionForProgramType(typeMain);
DexProgramClass upperBound = appView.definitionForProgramType(typeA);
DexProgramClass lowerBound = appView.definitionForProgramType(typeC);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
index e856ed2..2906ddd 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
@@ -59,7 +59,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
index 665ef74..42c441b 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
@@ -62,7 +62,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
index df0722f..67afdad 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
@@ -62,7 +62,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
index d4541ac..c6c6aac 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
index 6aac0fb..ada09f0 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
@@ -59,7 +59,8 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult =
+ appInfo.resolveMethodOnClassHolderLegacy(method);
assertTrue(resolutionResult.isSingleResolution());
DexType mainType = buildType(Main.class, appInfo.dexItemFactory());
DexProgramClass main = appView.definitionForProgramType(mainType);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
index a1f6b17..184b03f 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
@@ -62,7 +62,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
index 19f951a..a96b487 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
@@ -87,7 +87,7 @@
});
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(initial, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
DexProgramClass.asProgramClassOrNull(
appView
@@ -238,7 +238,7 @@
.build());
AppInfoWithClassHierarchy appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexType typeA = buildType(A.class, appInfo.dexItemFactory());
DexType typeB = buildType(B.class, appInfo.dexItemFactory());
DexProgramClass classB = appInfo.definitionForProgramType(typeB);
@@ -273,7 +273,7 @@
Unrelated.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Unrelated.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Unrelated.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
index 33bfc01..69ef032 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
@@ -62,7 +62,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Top.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(TopRunner.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
index 28d1cc2..b72f8b6 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
@@ -68,7 +68,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(
buildType(ViewModelRunner.class, appInfo.dexItemFactory()));
@@ -119,7 +119,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
@@ -171,7 +171,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(
buildType(ViewModelRunnerWithCast.class, appInfo.dexItemFactory()));
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
index 24aa358..2d10b18 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
@@ -61,7 +61,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(B.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
index 3ffdf09..87d27ee 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
@@ -54,7 +54,7 @@
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(builder.build(), Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
index 337ba95..0a3d14a 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
@@ -50,7 +50,7 @@
PackagePrivateChainTest.Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
index 8769eca..d1eb536 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolderLegacy(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
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 d68447d..e7b884c 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -34,12 +34,6 @@
private static final String JAVAC_LAMBDA_METHOD = "lambda$main$0";
- // TODO(b/172014416): These should not be needed once fixed.
- private static final String LAMBDA_BRIDGE_METHOD = "$r8$lambda$dX5OYTAgq4ijGUv_zaGoVsFINMs";
- private static final String INTERNAL_LAMBDA_CLASS =
- Main.class.getTypeName()
- + "$$InternalSyntheticLambda$0$11a5d582ed94e937718cf3ed497d4d164b60dfa85d606466457007fade57dce8$0";
-
@Parameters(name = "{0}")
public static TestParametersCollection parameters() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineSourceFileContextStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineSourceFileContextStackTrace.java
index eb1d9f3..f5943b5 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineSourceFileContextStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineSourceFileContextStackTrace.java
@@ -40,11 +40,9 @@
public List<String> retracedStackTrace() {
return Arrays.asList(
" at com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
- // TODO(b/226885646): Should be KotlinJavaSourceFileTestLibrary.kt
- + ".throwsException(KotlinJavaSourceFileTestLibrary.java:22)",
+ + ".throwsException(KotlinJavaSourceFileTestLibrary.kt:22)",
" at com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
- // TODO(b/226885646): Should be KotlinJavaSourceFileTestLibrary.kt
- + ".callsThrowsException(KotlinJavaSourceFileTestLibrary.java:19)",
+ + ".callsThrowsException(KotlinJavaSourceFileTestLibrary.kt:19)",
" at com.google.appreduce.remapper.KotlinJavaSourceFileTestObject"
+ ".main(KotlinJavaSourceFileTestObject.java:32)");
}
@@ -53,11 +51,9 @@
public List<String> retraceVerboseStackTrace() {
return Arrays.asList(
" at com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
- // TODO(b/226885646): Should be KotlinJavaSourceFileTestLibrary.kt
- + ".void throwsException()(KotlinJavaSourceFileTestLibrary.java:22)",
+ + ".void throwsException()(KotlinJavaSourceFileTestLibrary.kt:22)",
" at com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
- // TODO(b/226885646): Should be KotlinJavaSourceFileTestLibrary.kt
- + ".void callsThrowsException()(KotlinJavaSourceFileTestLibrary.java:19)",
+ + ".void callsThrowsException()(KotlinJavaSourceFileTestLibrary.kt:19)",
" at com.google.appreduce.remapper.KotlinJavaSourceFileTestObject"
+ ".void main(java.lang.String[])(KotlinJavaSourceFileTestObject.java:32)");
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
index 84bd1ef..b70b311 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.rewrite.assertions;
-import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBuilder;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.references.MethodReference;
@@ -70,10 +71,21 @@
protected abstract List<Path> getKotlinFiles() throws IOException;
+ protected boolean transformKotlinClasses() {
+ return false;
+ }
+
+ protected byte[] transformedKotlinClasses(Path kotlinClasses) throws IOException {
+ assert false;
+ return null;
+ }
+
protected abstract String getTestClassName();
protected void configureR8(R8FullTestBuilder builder) {}
+ protected void configureResultR8(R8TestCompileResult builder) {}
+
private Path kotlinStdlibLibraryForRuntime() throws Exception {
Path kotlinStdlibCf = kotlinc.getKotlinStdlibJar();
if (parameters.getRuntime().isCf()) {
@@ -107,6 +119,16 @@
}
}
+ private void addKotlinClasses(TestBuilder<?, ?> builder) {
+ builder.applyIf(
+ transformKotlinClasses(),
+ b ->
+ b.addProgramClassFileData(
+ transformedKotlinClasses(
+ compiledForAssertions.getForConfiguration(kotlinc, targetVersion))),
+ b -> b.addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion)));
+ }
+
@Test
public void testD8() throws Exception {
assumeTrue(parameters.isDexRuntime());
@@ -114,7 +136,7 @@
.apply(this::configureKotlinStdlib)
.setMinApi(parameters.getApiLevel())
.addProgramClasses(AssertionHandlers.class)
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .apply(this::addKotlinClasses)
.addAssertionsConfiguration(
builder ->
builder
@@ -131,7 +153,7 @@
.apply(this::configureKotlinStdlib)
.setMinApi(parameters.getApiLevel())
.addProgramClasses(AssertionHandlers.class)
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .apply(this::addKotlinClasses)
.addAssertionsConfiguration(
builder ->
builder
@@ -140,13 +162,8 @@
.build())
.addKeepMainRule(getTestClassName())
.apply(this::configureR8)
- .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary)
.compile()
- .applyIf(
- !kotlinStdlibAsLibrary,
- result ->
- result.assertAllWarningMessagesMatch(
- equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
+ .apply(this::configureResultR8)
.run(parameters.getRuntime(), getTestClassName())
.assertSuccessWithOutput(getExpectedOutput());
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerWithConditionsTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerWithConditionsTest.java
new file mode 100644
index 0000000..af2c8db
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerWithConditionsTest.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions;
+
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionsWithConditions;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerWithConditionsTest
+ extends AssertionConfigurationAssertionHandlerTestBase {
+
+ private static final String EXPECTED_OUTPUT =
+ StringUtils.lines(
+ "assertionHandler: assertionWithSimpleCondition",
+ "assertionHandler: assertionWithCondition");
+
+ @Override
+ String getExpectedOutput() {
+ return EXPECTED_OUTPUT;
+ }
+
+ @Override
+ MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ }
+
+ @Override
+ List<Class<?>> getTestClasses() {
+ return ImmutableList.of(AssertionsWithConditions.class);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsWithConditions.java b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsWithConditions.java
new file mode 100644
index 0000000..17d4d54
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsWithConditions.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions.assertionhandler;
+
+import com.android.tools.r8.Keep;
+
+public class AssertionsWithConditions {
+
+ @Keep
+ public static void assertionWithSimpleCondition(int x) {
+ assert x < 0;
+ }
+
+ private static boolean isZero(int x) {
+ return x == 0;
+ }
+
+ private static boolean isNegative(int x) {
+ return x < 0;
+ }
+
+ @Keep
+ public static void assertionWithCondition(int x, int y, int z) {
+ assert x == 0 && isZero(y) && isNegative(z);
+ }
+
+ public static void main(String[] args) {
+ assertionWithSimpleCondition(args.length);
+ assertionWithCondition(args.length, args.length, args.length);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionConfigurationAssertionHandlerKotlinDoubleCheckTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionConfigurationAssertionHandlerKotlinDoubleCheckTest.java
new file mode 100644
index 0000000..d0177bb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionConfigurationAssertionHandlerKotlinDoubleCheckTest.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions.kotlinassertionhandlerdoublecheck;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.AssertionConfigurationAssertionHandlerKotlinTestBase;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerKotlinDoubleCheckTest
+ extends AssertionConfigurationAssertionHandlerKotlinTestBase {
+
+ public AssertionConfigurationAssertionHandlerKotlinDoubleCheckTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions)
+ throws IOException {
+ super(parameters, kotlinParameters, kotlinStdlibAsClasspath, useJvmAssertions);
+ }
+
+ @Override
+ protected String getExpectedOutput() {
+ return StringUtils.lines("assertionHandler: doubleCheckAssertion");
+ }
+
+ @Override
+ protected MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ }
+
+ @Override
+ protected List<Path> getKotlinFiles() throws IOException {
+ return getKotlinFilesInTestPackage(getClass().getPackage());
+ }
+
+ @Override
+ protected boolean transformKotlinClasses() {
+ return true;
+ }
+
+ @Override
+ protected byte[] transformedKotlinClasses(Path kotlinClasses) throws IOException {
+ Path compiledKotlinClasses = temp.newFolder().toPath();
+ ZipUtils.unzip(
+ compiledForAssertions.getForConfiguration(kotlinc, targetVersion), compiledKotlinClasses);
+ String testClassPath =
+ DescriptorUtils.getPackageBinaryNameFromJavaType(getTestClassName())
+ + FileUtils.CLASS_EXTENSION;
+ String assertionsMockBinaryName =
+ DescriptorUtils.getPackageBinaryNameFromJavaType(
+ getClass().getPackage().getName() + ".AssertionsMock");
+ // Rewrite the static get on AssertionsMock.Enabled to static get on kotlin._Assertions.ENABLED
+ return transformer(
+ compiledKotlinClasses.resolve(testClassPath),
+ Reference.classFromTypeName(getTestClassName()))
+ .transformFieldInsnInMethod(
+ "doubleCheckAssertionsEnabled",
+ (opcode, owner, name, descriptor, continuation) -> {
+ continuation.visitFieldInsn(
+ opcode,
+ owner.equals(assertionsMockBinaryName) ? "kotlin/_Assertions" : owner,
+ name,
+ descriptor);
+ })
+ .transform();
+ }
+
+ @Override
+ protected String getTestClassName() {
+ return getClass().getPackage().getName() + ".AssertionDoubleCheckKt";
+ }
+
+ @Override
+ protected void configureR8(R8FullTestBuilder builder) {
+ boolean referencesNotNull =
+ !kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_3_72) && !kotlinStdlibAsLibrary;
+ builder.applyIf(referencesNotNull, b -> b.addDontWarn("org.jetbrains.annotations.NotNull"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionDoubleCheck.kt b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionDoubleCheck.kt
new file mode 100644
index 0000000..3351bcd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionDoubleCheck.kt
@@ -0,0 +1,28 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions.kotlinassertionhandlerdoublecheck
+
+fun doubleCheckAssertionsEnabled() {
+ // AssertionsMock.ENABLED will be rewritten to kotlin._Assertions.ENABLED to
+ // test
+ // * two checks on kotlin._Assertions.ENABLED and
+ // * check on both kotlin._Assertions.ENABLED and $assertionsDisabled
+ // before entering the assertion code.
+ //
+ // This is testing code like this found in kotlin-stdlib:
+ //
+ // if (_Assertions.ENABLED)
+ // assert(...) { ... }
+ // }
+ //
+ // E.g. in kotlin/io/files/FileTreeWalk.kt.
+ if (AssertionsMock.ENABLED) {
+ assert(false) { "doubleCheckAssertion" }
+ }
+}
+
+fun main() {
+ doubleCheckAssertionsEnabled();
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionsMock.kt b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionsMock.kt
new file mode 100644
index 0000000..bd05154
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerdoublecheck/AssertionsMock.kt
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions.kotlinassertionhandlerdoublecheck
+
+object AssertionsMock {
+ @JvmField
+ val ENABLED: Boolean = false
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
index e460253..aad753e 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
@@ -4,9 +4,12 @@
package com.android.tools.r8.rewrite.assertions.kotlinassertionhandlersimple;
+import static org.hamcrest.CoreMatchers.equalTo;
+
import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
@@ -62,6 +65,17 @@
!kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_3_72)
&& !kotlinStdlibAsLibrary
&& !useJvmAssertions;
- builder.applyIf(referencesNotNull, b -> b.addDontWarn("org.jetbrains.annotations.NotNull"));
+ builder
+ .applyIf(referencesNotNull, b -> b.addDontWarn("org.jetbrains.annotations.NotNull"))
+ .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary);
+ }
+
+ @Override
+ protected void configureResultR8(R8TestCompileResult builder) {
+ builder.applyIf(
+ !kotlinStdlibAsLibrary,
+ result ->
+ result.assertAllWarningMessagesMatch(
+ equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")));
}
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionConfigurationAssertionHandlerKotlinRethrowingTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionConfigurationAssertionHandlerKotlinRethrowingTest.java
index 93b3b57..c2848c3 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionConfigurationAssertionHandlerKotlinRethrowingTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionConfigurationAssertionHandlerKotlinRethrowingTest.java
@@ -4,8 +4,11 @@
package com.android.tools.r8.rewrite.assertions.kotlinassertionhandlerwithexceptions;
+import static org.hamcrest.CoreMatchers.equalTo;
+
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
@@ -66,6 +69,16 @@
builder
.addKeepRules("-keep class **.*Kt { assertionsWith*(); simpleAssertion(); }")
.addDontWarn("org.jetbrains.annotations.NotNull")
- .applyIf(!kotlinStdlibAsLibrary, b -> b.addDontWarn("org.jetbrains.annotations.Nullable"));
+ .applyIf(!kotlinStdlibAsLibrary, b -> b.addDontWarn("org.jetbrains.annotations.Nullable"))
+ .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary);
+ }
+
+ @Override
+ protected void configureResultR8(R8TestCompileResult builder) {
+ builder.applyIf(
+ !kotlinStdlibAsLibrary,
+ result ->
+ result.assertAllWarningMessagesMatch(
+ equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")));
}
}
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 604caae..bb63e6f 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -86,7 +86,7 @@
"Hello!", "Unexpected outcome of checkcast", "Goodbye!", "");
case V7_0_0:
- case V13_MASTER:
+ case V13_0_0:
return StringUtils.joinLines(
"Hello!",
"Unexpected outcome of checkcast",
diff --git a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
index 3a32244..d3b8c48 100644
--- a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
+++ b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
@@ -100,7 +100,7 @@
DexMethod helloReference = buildNullaryVoidMethod(HelloGreeter.class, "hello", dexItemFactory);
assertTrue(
appInfo
- .resolveMethodOnClassHolder(helloReference)
+ .resolveMethodOnClassHolderLegacy(helloReference)
.isAccessibleFrom(context, appView)
.isTrue());
@@ -108,7 +108,7 @@
DexMethod worldReference = buildNullaryVoidMethod(WorldGreeter.class, "world", dexItemFactory);
assertTrue(
appInfo
- .resolveMethodOnClassHolder(worldReference)
+ .resolveMethodOnClassHolderLegacy(worldReference)
.isAccessibleFrom(context, appView)
.isFalse());
}
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/MultipleRulesRegression228791247Test.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/MultipleRulesRegression228791247Test.java
new file mode 100644
index 0000000..c61fa16
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/MultipleRulesRegression228791247Test.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.shaking.methods.interfaces;
+
+import static com.android.tools.r8.references.Reference.classFromClass;
+
+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 MultipleRulesRegression228791247Test extends TestBase {
+
+ private static final String EXPECTED = StringUtils.lines("Hello!");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public MultipleRulesRegression228791247Test(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testReference() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, J.class, A.class, TestClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // Regression adds two rules causes the forwarding method to be generated twice.
+ String rule1 = "-keep class " + classFromClass(J.class).getTypeName() + "{ void *oo(); }";
+ String rule2 = "-keep class " + classFromClass(J.class).getTypeName() + "{ void fo*(); }";
+ testForR8(parameters.getBackend())
+ .addProgramClasses(I.class, J.class, A.class, TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(rule1, rule2)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ public interface I {
+ default void foo() {
+ if (System.nanoTime() > 0) {
+ System.out.println("Hello!");
+ }
+ }
+ }
+
+ public interface J extends I {
+ // No foo, but it will be kept at J::foo.
+ }
+
+ public static class A implements J {}
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ J j = System.nanoTime() > 0 ? new A() : null;
+ j.foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/FeatureClassMappingTest.java b/src/test/java/com/android/tools/r8/utils/FeatureClassMappingTest.java
deleted file mode 100644
index f41be5c..0000000
--- a/src/test/java/com/android/tools/r8/utils/FeatureClassMappingTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) 2016, 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.utils;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertFalse;
-
-import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
-import com.google.common.collect.ImmutableList;
-import java.util.List;
-import org.junit.Test;
-
-public class FeatureClassMappingTest {
-
- @Test
- public void testSimpleParse() throws Exception {
-
- List<String> lines =
- ImmutableList.of(
- "# Comment, don't care about contents: even more ::::",
- "com.google.base:base",
- "", // Empty lines allowed
- "com.google.feature1:feature1",
- "com.google.feature1:feature1", // Multiple definitions of the same predicate allowed.
- "com.google$:feature1",
- "_com.google:feature21",
- "com.google.*:feature32");
- FeatureClassMapping mapping = new FeatureClassMapping(lines);
- }
-
- private void ensureThrowsMappingException(List<String> lines) {
- try {
- new FeatureClassMapping(lines);
- assertFalse(true);
- } catch (FeatureMappingException e) {
- // Expected
- }
- }
-
- private void ensureThrowsMappingException(String string) {
- ensureThrowsMappingException(ImmutableList.of(string));
- }
-
- @Test
- public void testLookup() throws Exception {
- List<String> lines =
- ImmutableList.of(
- "com.google.Base:base",
- "",
- "com.google.Feature1:feature1",
- "com.google.Feature1:feature1", // Multiple definitions of the same predicate allowed.
- "com.google.different.*:feature1",
- "_com.Google:feature21",
- "com.google.bas42.*:feature42");
- FeatureClassMapping mapping = new FeatureClassMapping(lines);
- assertEquals(mapping.featureForClass("com.google.Feature1"), "feature1");
- assertEquals(mapping.featureForClass("com.google.different.Feature1"), "feature1");
- assertEquals(mapping.featureForClass("com.google.different.Foobar"), "feature1");
- assertEquals(mapping.featureForClass("com.google.Base"), "base");
- assertEquals(mapping.featureForClass("com.google.bas42.foo.bar.bar.Foo"), "feature42");
- assertEquals(mapping.featureForClass("com.google.bas42.f$o$o$.bar43.bar.Foo"), "feature42");
- assertEquals(mapping.featureForClass("_com.Google"), "feature21");
- }
-
- @Test
- public void testCatchAllWildcards() throws Exception {
- testBaseWildcard(true);
- testBaseWildcard(false);
- testNonBaseCatchAll();
- }
-
- private void testNonBaseCatchAll() throws FeatureMappingException {
- List<String> lines =
- ImmutableList.of(
- "com.google.Feature1:feature1",
- "*:nonbase",
- "com.strange.*:feature2");
- FeatureClassMapping mapping = new FeatureClassMapping(lines);
- assertEquals(mapping.featureForClass("com.google.Feature1"), "feature1");
- assertEquals(mapping.featureForClass("com.google.different.Feature1"), "nonbase");
- assertEquals(mapping.featureForClass("com.strange.different.Feature1"), "feature2");
- assertEquals(mapping.featureForClass("Feature1"), "nonbase");
- assertEquals(mapping.featureForClass("a.b.z.A"), "nonbase");
- }
-
- private void testBaseWildcard(boolean explicitBase) throws FeatureMappingException {
- List<String> lines =
- ImmutableList.of(
- "com.google.Feature1:feature1",
- explicitBase ? "*:base" : "",
- "com.strange.*:feature2");
- FeatureClassMapping mapping = new FeatureClassMapping(lines);
- assertEquals(mapping.featureForClass("com.google.Feature1"), "feature1");
- assertEquals(mapping.featureForClass("com.google.different.Feature1"), "base");
- assertEquals(mapping.featureForClass("com.strange.different.Feature1"), "feature2");
- assertEquals(mapping.featureForClass("com.stranger.Clazz"), "base");
- assertEquals(mapping.featureForClass("Feature1"), "base");
- assertEquals(mapping.featureForClass("a.b.z.A"), "base");
- }
-
- @Test
- public void testWrongLines() throws Exception {
- // No colon.
- ensureThrowsMappingException("foo");
- ensureThrowsMappingException("com.google.base");
- // Two colons.
- ensureThrowsMappingException(ImmutableList.of("a:b:c"));
-
- // Empty identifier.
- ensureThrowsMappingException("com..google:feature1");
-
- // Ambiguous redefinition
- ensureThrowsMappingException(
- ImmutableList.of("com.google.foo:feature1", "com.google.foo:feature2"));
- ensureThrowsMappingException(
- ImmutableList.of("com.google.foo.*:feature1", "com.google.foo.*:feature2"));
- }
-
- @Test
- public void testUsesOnlyExactMappings() throws Exception {
- List<String> lines =
- ImmutableList.of(
- "com.pkg1.Clazz:feature1",
- "com.pkg2.Clazz:feature2");
- FeatureClassMapping mapping = new FeatureClassMapping(lines);
-
- assertEquals(mapping.featureForClass("com.pkg1.Clazz"), "feature1");
- assertEquals(mapping.featureForClass("com.pkg2.Clazz"), "feature2");
- assertEquals(mapping.featureForClass("com.pkg1.Other"), mapping.baseName);
- }
-}
diff --git a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
index 27356f7..0f2a679 100644
--- a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
+++ b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
@@ -1 +1 @@
-175091160988fe534b90b70308ac0f7c489e48ec
\ No newline at end of file
+cec0d3cf2655ac9c77410ddf87a7b4e5900858a5
\ No newline at end of file
diff --git a/tools/apk_masseur.py b/tools/apk_masseur.py
index b363bb7..a4a010b 100755
--- a/tools/apk_masseur.py
+++ b/tools/apk_masseur.py
@@ -45,9 +45,6 @@
apk = args[0]
return (options, apk)
-def findKeystore():
- return os.path.join(os.getenv('HOME'), '.android', 'app.keystore')
-
def repack(apk, processed_out, resources, temp, quiet, logging):
processed_apk = os.path.join(temp, 'processed.apk')
shutil.copyfile(apk, processed_apk)
@@ -80,25 +77,13 @@
def sign(unsigned_apk, keystore, temp, quiet, logging):
signed_apk = os.path.join(temp, 'unaligned.apk')
- apk_utils.sign_with_apksigner(
+ return apk_utils.sign_with_apksigner(
unsigned_apk, signed_apk, keystore, quiet=quiet, logging=logging)
- return signed_apk
def align(signed_apk, temp, quiet, logging):
utils.Print('Aligning', quiet=quiet)
aligned_apk = os.path.join(temp, 'aligned.apk')
- zipalign_path = (
- 'zipalign' if 'build_tools' in os.environ.get('PATH')
- else os.path.join(utils.getAndroidBuildTools(), 'zipalign'))
- cmd = [
- zipalign_path,
- '-f',
- '4',
- signed_apk,
- aligned_apk
- ]
- utils.RunCmd(cmd, quiet=quiet, logging=logging)
- return signed_apk
+ return apk_utils.align(signed_apk, aligned_apk)
def masseur(
apk, dex=None, resources=None, out=None, adb_options=None, keystore=None,
@@ -106,7 +91,7 @@
if not out:
out = os.path.basename(apk)
if not keystore:
- keystore = findKeystore()
+ keystore = apk_utils.default_keystore()
with utils.TempDir() as temp:
processed_apk = None
if dex:
diff --git a/tools/apk_utils.py b/tools/apk_utils.py
index c3c616b..86d3b0f 100755
--- a/tools/apk_utils.py
+++ b/tools/apk_utils.py
@@ -5,9 +5,13 @@
import optparse
import os
+import shutil
import subprocess
import sys
+import time
+
import utils
+import zip_utils
USAGE = 'usage: %prog [options] <apk>'
@@ -34,6 +38,30 @@
apk = args[0]
return (options, apk)
+def add_baseline_profile_to_apk(apk, baseline_profile, tmp_dir):
+ if baseline_profile is None:
+ return apk
+ ts = time.time_ns()
+ dest_apk = os.path.join(tmp_dir, 'app-%s.apk' % ts)
+ dest_apk_aligned = os.path.join(tmp_dir, 'app-aligned-%s.apk' % ts)
+ dest_apk_signed = os.path.join(tmp_dir, 'app-signed-%s.apk' % ts)
+ shutil.copy2(apk, dest_apk)
+ zip_utils.add_file_to_zip(
+ baseline_profile, 'assets/dexopt/baseline.prof', dest_apk)
+ align(dest_apk, dest_apk_aligned)
+ sign_with_apksigner(dest_apk_aligned, dest_apk_signed)
+ return dest_apk_signed
+
+def align(apk, aligned_apk):
+ zipalign_path = (
+ 'zipalign' if 'build_tools' in os.environ.get('PATH')
+ else os.path.join(utils.getAndroidBuildTools(), 'zipalign'))
+ cmd = [zipalign_path, '-f', '4', apk, aligned_apk]
+ utils.RunCmd(cmd, quiet=True, logging=False)
+ return aligned_apk
+
+def default_keystore():
+ return os.path.join(os.getenv('HOME'), '.android', 'app.keystore')
def sign(unsigned_apk, signed_apk, keystore, quiet=False, logging=True):
utils.Print('Signing (ignore the warnings)', quiet=quiet)
@@ -52,20 +80,20 @@
utils.RunCmd(cmd, quiet=quiet)
def sign_with_apksigner(
- unsigned_apk, signed_apk, keystore, password='android', quiet=False,
+ unsigned_apk, signed_apk, keystore=None, password='android', quiet=False,
logging=True):
cmd = [
os.path.join(utils.getAndroidBuildTools(), 'apksigner'),
'sign',
'-v',
- '--ks', keystore,
+ '--ks', keystore or default_keystore(),
'--ks-pass', 'pass:' + password,
'--min-sdk-version', '19',
'--out', signed_apk,
unsigned_apk
]
utils.RunCmd(cmd, quiet=quiet, logging=logging)
-
+ return signed_apk
def main():
(options, apk) = parse_options()
diff --git a/tools/archive.py b/tools/archive.py
index 893fc19..d7bf1a9 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -33,22 +33,13 @@
type="string", action="store")
return result.parse_args()
-def GetToolVersion(jar_path):
- # TODO(mkroghj) This would not work for r8-lib, maybe use utils.getR8Version.
- output = subprocess.check_output([
- jdk.GetJavaExecutable(), '-jar', jar_path, '--version'
- ]).decode('utf-8')
- return output.splitlines()[0].strip()
-
def GetVersion():
- r8_version = GetToolVersion(utils.R8_JAR)
- d8_version = GetToolVersion(utils.D8_JAR)
- # The version printed is "D8 vVERSION_NUMBER" and "R8 vVERSION_NUMBER"
- # Sanity check that versions match.
- if d8_version.split()[1] != r8_version.split()[1]:
- raise Exception(
- 'Version mismatch: \n%s\n%s' % (d8_version, r8_version))
- return d8_version.split()[1]
+ output = subprocess.check_output([
+ jdk.GetJavaExecutable(), '-cp', utils.R8_JAR, 'com.android.tools.r8.R8',
+ '--version'
+ ]).decode('utf-8')
+ r8_version = output.splitlines()[0].strip()
+ return r8_version.split()[1]
def GetGitBranches():
return subprocess.check_output(['git', 'show', '-s', '--pretty=%d', 'HEAD'])
@@ -157,7 +148,6 @@
# The '-Pno_internal' flag is important because we generate the lib based on uses in tests.
gradle.RunGradle([
utils.R8,
- utils.D8,
utils.R8LIB,
utils.R8LIB_NO_DEPS,
utils.R8RETRACE,
@@ -193,7 +183,6 @@
create_maven_release.write_default_r8_pom_file(default_pom_file, version)
for file in [
- utils.D8_JAR,
utils.R8_JAR,
utils.R8LIB_JAR,
utils.R8LIB_JAR + '.map',
diff --git a/tools/dexsplitter.py b/tools/dexsplitter.py
deleted file mode 100755
index a97d089..0000000
--- a/tools/dexsplitter.py
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2018, 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.
-
-import sys
-import toolhelper
-
-if __name__ == '__main__':
- sys.exit(toolhelper.run('dexsplitter', sys.argv[1:]))
diff --git a/tools/gradle.py b/tools/gradle.py
index 19fa773..92503a7 100755
--- a/tools/gradle.py
+++ b/tools/gradle.py
@@ -59,10 +59,10 @@
GRADLE, GRADLE_TGZ, GRADLE_SHA1, 'Gradle binary')
def EnsureJdk():
- jdkHome = jdk.GetJdkHome()
- jdkTgz = jdkHome + '.tar.gz'
+ jdkRoot = jdk.GetJdkRoot()
+ jdkTgz = jdkRoot + '.tar.gz'
jdkSha1 = jdkTgz + '.sha1'
- utils.EnsureDepFromGoogleCloudStorage(jdkHome, jdkTgz, jdkSha1, 'JDK')
+ utils.EnsureDepFromGoogleCloudStorage(jdkRoot, jdkTgz, jdkSha1, 'JDK')
def EnsureDeps():
EnsureGradle()
diff --git a/tools/internal_test.py b/tools/internal_test.py
index 8e4caa5..45dd694 100755
--- a/tools/internal_test.py
+++ b/tools/internal_test.py
@@ -189,7 +189,7 @@
return utils.get_HEAD_sha1()
def get_test_result_dir():
- return os.path.join(utils.R8_TEST_RESULTS_BUCKET, TEST_RESULT_DIR)
+ return os.path.join(utils.R8_INTERNAL_TEST_RESULTS_BUCKET, TEST_RESULT_DIR)
def get_sha_destination(sha):
return os.path.join(get_test_result_dir(), sha)
@@ -287,6 +287,9 @@
print('Tests failed, you can print the logs by running(googlers only):')
print(' tools/internal_test.py --print_logs %s' % git_hash)
return 1
+ else:
+ print(' Test validation of archiving logs, see b/177799191')
+ print(' tools/internal_test.py --print_logs %s' % git_hash)
def run_continuously():
# If this script changes, we will restart ourselves
@@ -374,7 +377,7 @@
stderr_fd.close()
if stdout_fd:
stdout_fd.close()
- if exitcode != 0:
+ if exitcode != 0 or True:
handle_output(archive, stderr, stdout, popen.returncode,
timed_out, ' '.join(cmd))
return exitcode
diff --git a/tools/jdk.py b/tools/jdk.py
index c9cb628..5cf1465 100755
--- a/tools/jdk.py
+++ b/tools/jdk.py
@@ -13,7 +13,10 @@
def GetJdkHome():
return GetJdk11Home()
-def GetJdk11Home():
+def GetJdkRoot():
+ return GetJdk11Root()
+
+def GetJdk11Root():
root = os.path.join(JDK_DIR, 'jdk-11')
if defines.IsLinux():
return os.path.join(root, 'linux')
@@ -24,6 +27,14 @@
else:
return os.environ['JAVA_HOME']
+def GetJdk11Home():
+ root = GetJdk11Root()
+ # osx has the home inside Contents/Home in the bundle
+ if defines.IsOsX():
+ return os.path.join(root,'Contents', 'Home')
+ else:
+ return root
+
def GetJdk9Home():
root = os.path.join(JDK_DIR, 'openjdk-9.0.4')
if defines.IsLinux():
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions
index fee679c..02e81cd 100644
--- a/tools/linux/README.art-versions
+++ b/tools/linux/README.art-versions
@@ -42,9 +42,9 @@
<continue with repo sync as above>
-art-13-master (Android T)
--------------------------
-Build from master commit e208b04cc2efaf707390d7acbe8f978142701d72.
+art-13 (Android T)
+------------------
+Build from tm-dev commit 442e1091f39417c692d91609af05e58af60d8e2b.
repo sync -cq -j24
source build/envsetup.sh
@@ -53,16 +53,16 @@
m -j48 build-art
m -j48 test-art-host
-Collected into tools/linux/host/art-13-master. The "host" path element is checked
+Collected into tools/linux/host/art-13. The "host" path element is checked
by the script for running Art.
cd <r8 checkout>
scripts/update-host-art.sh \
- --android-checkout <...>/android/master \
- --art-dir host/art-13-master \
+ --android-checkout <...>/android/tm-dev \
+ --art-dir host/art-13 \
--android-product redfin
-(cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-13-master)
+(cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-13)
art-12.0.0 (Android S)
---------------------
diff --git a/tools/linux/host/art-13-dev.tar.gz.sha1 b/tools/linux/host/art-13-dev.tar.gz.sha1
new file mode 100644
index 0000000..5367655
--- /dev/null
+++ b/tools/linux/host/art-13-dev.tar.gz.sha1
@@ -0,0 +1 @@
+fed34a1eecaf012550cdd9df24434b8b2068a194
\ No newline at end of file
diff --git a/tools/linux/host/art-13-master.tar.gz.sha1 b/tools/linux/host/art-13-master.tar.gz.sha1
deleted file mode 100644
index 8b16edd..0000000
--- a/tools/linux/host/art-13-master.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a2cf2b34b8712adb5c25a18bc6135946cfb1a047
\ No newline at end of file
diff --git a/tools/startup/adb_utils.py b/tools/startup/adb_utils.py
index 981bcbd..7f1d3bc 100644
--- a/tools/startup/adb_utils.py
+++ b/tools/startup/adb_utils.py
@@ -4,11 +4,33 @@
# BSD-style license that can be found in the LICENSE file.
from enum import Enum
+import os
import subprocess
+import sys
+import threading
import time
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+import utils
+
DEVNULL=subprocess.DEVNULL
+class ProcessReader(threading.Thread):
+
+ def __init__(self, process):
+ threading.Thread.__init__(self)
+ self.lines = []
+ self.process = process
+
+ def run(self):
+ for line in self.process.stdout:
+ line = line.decode('utf-8').strip()
+ self.lines.append(line)
+
+ def stop(self):
+ self.process.kill()
+
class ScreenState(Enum):
OFF_LOCKED = 1,
OFF_UNLOCKED = 2
@@ -27,6 +49,11 @@
def is_on_and_unlocked(self):
return self == ScreenState.ON_UNLOCKED
+def broadcast(action, component, device_id=None):
+ print('Sending broadcast %s' % action)
+ cmd = create_adb_cmd('shell am broadcast -a %s %s' % (action, component), device_id)
+ return subprocess.check_output(cmd).decode('utf-8').strip().splitlines()
+
def create_adb_cmd(arguments, device_id=None):
assert isinstance(arguments, list) or isinstance(arguments, str)
cmd = ['adb']
@@ -39,7 +66,7 @@
def capture_app_profile_data(app_id, device_id=None):
cmd = create_adb_cmd(
'shell killall -s SIGUSR1 %s' % app_id, device_id)
- subprocess.check_output(cmd)
+ subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
time.sleep(5)
def check_app_has_profile_data(app_id, device_id=None):
@@ -54,6 +81,10 @@
if size == 4:
raise ValueError('Expected size of profile at %s to be > 4K' % profile_path)
+def clear_logcat(device_id=None):
+ cmd = create_adb_cmd('logcat -c', device_id)
+ subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
def clear_profile_data(app_id, device_id=None):
cmd = create_adb_cmd(
'shell cmd package compile --reset %s' % app_id, device_id)
@@ -65,11 +96,13 @@
subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
def force_compilation(app_id, device_id=None):
+ print('Applying AOT (full)')
cmd = create_adb_cmd(
'shell cmd package compile -m speed -f %s' % app_id, device_id)
subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
def force_profile_compilation(app_id, device_id=None):
+ print('Applying AOT (profile)')
cmd = create_adb_cmd(
'shell cmd package compile -m speed-profile -f %s' % app_id, device_id)
subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
@@ -86,6 +119,15 @@
'Expected stdout to end with ".apk", was: %s' % stdout)
return apk_path
+def get_profile_data(app_id, device_id=None):
+ with utils.TempDir() as temp:
+ source = get_profile_path(app_id)
+ target = os.path.join(temp, 'primary.prof')
+ cmd = create_adb_cmd('pull %s %s' % (source, target), device_id)
+ subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+ with open(target, 'rb') as f:
+ return f.read()
+
def get_profile_path(app_id):
return '/data/misc/profiles/cur/0/%s/primary.prof' % app_id
@@ -170,10 +212,23 @@
return screen_off_timeout
def install(apk, device_id=None):
+ print('Installing %s' % apk)
cmd = create_adb_cmd('install %s' % apk, device_id)
stdout = subprocess.check_output(cmd).decode('utf-8')
assert 'Success' in stdout
+def install_profile(app_id, device_id=None):
+ # This assumes that the profileinstaller library has been added to the app,
+ # https://developer.android.com/jetpack/androidx/releases/profileinstaller.
+ action = 'androidx.profileinstaller.action.INSTALL_PROFILE'
+ component = '%s/androidx.profileinstaller.ProfileInstallReceiver' % app_id
+ stdout = broadcast(action, component, device_id)
+ assert len(stdout) == 2
+ assert stdout[0] == ('Broadcasting: Intent { act=%s flg=0x400000 cmp=%s }' % (action, component))
+ assert stdout[1] == 'Broadcast completed: result=1', stdout[1]
+ stop_app(app_id, device_id)
+ force_profile_compilation(app_id, device_id)
+
def issue_key_event(key_event, device_id=None, sleep_in_seconds=1):
cmd = create_adb_cmd('shell input keyevent %s' % key_event, device_id)
stdout = subprocess.check_output(cmd).decode('utf-8').strip()
@@ -200,6 +255,10 @@
assert not wait_for_activity_to_launch or 'total_time' in result
return result
+def navigate_to_home_screen(device_id=None):
+ cmd = create_adb_cmd('shell input keyevent KEYCODE_HOME', device_id)
+ subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
def prepare_for_interaction_with_device(device_id=None, device_pin=None):
# Increase screen off timeout to avoid device screen turns off.
twenty_four_hours_in_millis = 24 * 60 * 60 * 1000
@@ -226,7 +285,26 @@
stdout = subprocess.check_output(cmd).decode('utf-8').strip()
assert len(stdout) == 0
+def start_logcat(device_id=None, format=None, filter=None):
+ args = ['logcat']
+ if format:
+ args.extend(['--format', format])
+ if filter:
+ args.append(filter)
+ cmd = create_adb_cmd(args, device_id)
+ logcat_process = subprocess.Popen(
+ cmd, bufsize=1024*1024, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ reader = ProcessReader(logcat_process)
+ reader.start()
+ return reader
+
+def stop_logcat(logcat_reader):
+ logcat_reader.stop()
+ logcat_reader.join()
+ return logcat_reader.lines
+
def stop_app(app_id, device_id=None):
+ print('Shutting down %s' % app_id)
cmd = create_adb_cmd('shell am force-stop %s' % app_id, device_id)
subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
@@ -237,6 +315,7 @@
device_id)
def uninstall(app_id, device_id=None):
+ print('Uninstalling %s' % app_id)
cmd = create_adb_cmd('uninstall %s' % app_id, device_id)
process_result = subprocess.run(cmd, capture_output=True)
stdout = process_result.stdout.decode('utf-8')
@@ -246,7 +325,8 @@
else:
expected_error = (
'java.lang.IllegalArgumentException: Unknown package: %s' % app_id)
- assert expected_error in stderr
+ assert 'Failure [DELETE_FAILED_INTERNAL_ERROR]' in stdout \
+ or expected_error in stderr
def unlock(device_id=None, device_pin=None):
screen_state = get_screen_state(device_id)
diff --git a/tools/startup/generate_startup_descriptors.py b/tools/startup/generate_startup_descriptors.py
index ea0fdf3..f1faee43 100755
--- a/tools/startup/generate_startup_descriptors.py
+++ b/tools/startup/generate_startup_descriptors.py
@@ -6,16 +6,23 @@
import adb_utils
import argparse
+import os
import sys
import time
def extend_startup_descriptors(startup_descriptors, iteration, options):
- generate_startup_profile_on_device(options)
- classes_and_methods = adb_utils.get_classes_and_methods_from_app_profile(
- options.app_id, options.device_id)
- current_startup_descriptors = \
- transform_classes_and_methods_to_r8_startup_descriptors(
- classes_and_methods, options)
+ (logcat, profile, profile_classes_and_methods) = \
+ generate_startup_profile(options)
+ if options.logcat:
+ write_tmp_logcat(logcat, iteration, options)
+ current_startup_descriptors = get_r8_startup_descriptors_from_logcat(logcat)
+ else:
+ write_tmp_profile(profile, iteration, options)
+ write_tmp_profile_classes_and_methods(profile_classes_and_methods, iteration, options)
+ current_startup_descriptors = \
+ transform_classes_and_methods_to_r8_startup_descriptors(
+ profile_classes_and_methods, options)
+ write_tmp_startup_descriptors(current_startup_descriptors, iteration, options)
number_of_new_startup_descriptors = add_r8_startup_descriptors(
startup_descriptors, current_startup_descriptors)
if options.out is not None:
@@ -24,15 +31,32 @@
% (number_of_new_startup_descriptors, iteration + 1))
return number_of_new_startup_descriptors
-def generate_startup_profile_on_device(options):
- if not options.use_existing_profile:
- # Clear existing profile data.
- adb_utils.clear_profile_data(options.app_id, options.device_id)
-
+def generate_startup_profile(options):
+ logcat = None
+ profile = None
+ profile_classes_and_methods = None
+ if options.use_existing_profile:
+ # Verify presence of profile.
+ adb_utils.check_app_has_profile_data(options.app_id, options.device_id)
+ profile = adb_utils.get_profile_data(options.app_id, options.device_id)
+ profile_classes_and_methods = \
+ adb_utils.get_classes_and_methods_from_app_profile(
+ options.app_id, options.device_id)
+ else:
# Unlock device.
tear_down_options = adb_utils.prepare_for_interaction_with_device(
options.device_id, options.device_pin)
+ logcat_process = None
+ if options.logcat:
+ # Clear logcat and start capturing logcat.
+ adb_utils.clear_logcat(options.device_id)
+ logcat_process = adb_utils.start_logcat(
+ options.device_id, format='raw', filter='r8:I *:S')
+ else:
+ # Clear existing profile data.
+ adb_utils.clear_profile_data(options.app_id, options.device_id)
+
# Launch activity to generate startup profile on device.
adb_utils.launch_activity(
options.app_id, options.main_activity, options.device_id)
@@ -40,17 +64,36 @@
# Wait for activity startup.
time.sleep(options.startup_duration)
- # Capture startup profile.
- adb_utils.capture_app_profile_data(options.app_id, options.device_id)
+ if options.logcat:
+ # Get startup descriptors from logcat.
+ logcat = adb_utils.stop_logcat(logcat_process)
+ else:
+ # Capture startup profile.
+ adb_utils.capture_app_profile_data(options.app_id, options.device_id)
+ profile = adb_utils.get_profile_data(options.app_id, options.device_id)
+ profile_classes_and_methods = \
+ adb_utils.get_classes_and_methods_from_app_profile(
+ options.app_id, options.device_id)
# Shutdown app.
adb_utils.stop_app(options.app_id, options.device_id)
-
adb_utils.tear_down_after_interaction_with_device(
tear_down_options, options.device_id)
- # Verify presence of profile.
- adb_utils.check_app_has_profile_data(options.app_id, options.device_id)
+ return (logcat, profile, profile_classes_and_methods)
+
+def get_r8_startup_descriptors_from_logcat(logcat):
+ startup_descriptors = []
+ for line in logcat:
+ if line == '--------- beginning of main':
+ continue
+ if line == '--------- beginning of system':
+ continue
+ if not line.startswith('L') or not line.endswith(';'):
+ print('Unrecognized line in logcat: %s' % line)
+ continue
+ startup_descriptors.append(line)
+ return startup_descriptors
def transform_classes_and_methods_to_r8_startup_descriptors(
classes_and_methods, options):
@@ -72,6 +115,53 @@
return new_number_of_startup_descriptors \
- previous_number_of_startup_descriptors
+def write_tmp_binary_artifact(artifact, iteration, options, name):
+ if not options.tmp_dir:
+ return
+ out_dir = os.path.join(options.tmp_dir, str(iteration))
+ os.makedirs(out_dir, exist_ok=True)
+ path = os.path.join(out_dir, name)
+ with open(path, 'wb') as f:
+ f.write(artifact)
+
+def write_tmp_textual_artifact(artifact, iteration, options, name, item_to_string=None):
+ if not options.tmp_dir:
+ return
+ out_dir = os.path.join(options.tmp_dir, str(iteration))
+ os.makedirs(out_dir, exist_ok=True)
+ path = os.path.join(out_dir, name)
+ with open(path, 'w') as f:
+ for item in artifact:
+ f.write(item if item_to_string is None else item_to_string(item))
+ f.write('\n')
+
+def write_tmp_logcat(logcat, iteration, options):
+ write_tmp_textual_artifact(logcat, iteration, options, 'logcat.txt')
+
+def write_tmp_profile(profile, iteration, options):
+ write_tmp_binary_artifact(profile, iteration, options, 'primary.prof')
+
+def write_tmp_profile_classes_and_methods(
+ profile_classes_and_methods, iteration, options):
+ def item_to_string(item):
+ descriptor = item.get('descriptor')
+ flags = item.get('flags')
+ return '%s%s%s%s' % (
+ 'H' if flags.get('hot') else '',
+ 'S' if flags.get('startup') else '',
+ 'P' if flags.get('post_startup') else '',
+ descriptor)
+ write_tmp_textual_artifact(
+ profile_classes_and_methods,
+ iteration,
+ options,
+ 'profile.txt',
+ item_to_string)
+
+def write_tmp_startup_descriptors(startup_descriptors, iteration, options):
+ write_tmp_textual_artifact(
+ startup_descriptors, iteration, options, 'startup-descriptors.txt')
+
def parse_options(argv):
result = argparse.ArgumentParser(
description='Generate a perfetto trace file.')
@@ -84,6 +174,9 @@
help='Device id (e.g., emulator-5554).')
result.add_argument('--device-pin',
help='Device pin code (e.g., 1234)')
+ result.add_argument('--logcat',
+ action='store_true',
+ default=False)
result.add_argument('--include-post-startup',
help='Include post startup classes and methods in the R8 '
'startup descriptors',
@@ -102,6 +195,9 @@
help='Duration in seconds before shutting down app',
default=15,
type=int)
+ result.add_argument('--tmp-dir',
+ help='Directory where to store intermediate artifacts'
+ ' (by default these are not emitted)')
result.add_argument('--until-stable',
help='Repeat profile generation until no new startup '
'descriptors are found',
diff --git a/tools/startup/measure_startup.py b/tools/startup/measure_startup.py
index 080f827..f0b2ce9 100755
--- a/tools/startup/measure_startup.py
+++ b/tools/startup/measure_startup.py
@@ -20,6 +20,7 @@
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import adb_utils
+import apk_utils
import perfetto_utils
import utils
@@ -45,13 +46,13 @@
tear_down_options['previous_screen_off_timeout'],
options.device_id)
-def run_all(options, tmp_dir):
+def run_all(apk, options, tmp_dir):
# Launch app while collecting information.
data_avg = {}
for iteration in range(options.iterations):
print('Starting iteration %i' % iteration)
out_dir = os.path.join(options.out_dir, str(iteration))
- prepare_for_run(out_dir, options)
+ prepare_for_run(apk, out_dir, options)
data = run(out_dir, options, tmp_dir)
add_data(data_avg, data)
print("Result:")
@@ -64,20 +65,25 @@
print(data_avg)
write_data(options.out_dir, data_avg)
-def prepare_for_run(out_dir, options):
+def prepare_for_run(apk, out_dir, options):
adb_utils.root(options.device_id)
adb_utils.uninstall(options.app_id, options.device_id)
- adb_utils.install(options.apk, options.device_id)
- adb_utils.clear_profile_data(options.app_id, options.device_id)
+ adb_utils.install(apk, options.device_id)
if options.aot:
- adb_utils.force_compilation(options.app_id, options.device_id)
- elif options.aot_profile:
+ if options.baseline_profile:
+ adb_utils.clear_profile_data(options.app_id, options.device_id)
+ adb_utils.install_profile(options.app_id, options.device_id)
+ else:
+ adb_utils.force_compilation(options.app_id, options.device_id)
+ if options.hot_startup:
adb_utils.launch_activity(
- options.app_id, options.main_activity, options.device_id)
- time.sleep(options.aot_profile_sleep)
- adb_utils.stop_app(options.app_id, options.device_id)
- adb_utils.force_profile_compilation(options.app_id, options.device_id)
-
+ options.app_id,
+ options.main_activity,
+ options.device_id,
+ wait_for_activity_to_launch=False)
+ time.sleep(options.startup_duration)
+ adb_utils.navigate_to_home_screen(options.device_id)
+ time.sleep(1)
adb_utils.drop_caches(options.device_id)
os.makedirs(out_dir, exist_ok=True)
@@ -87,9 +93,9 @@
# Start perfetto trace collector.
perfetto_process = None
perfetto_trace_path = None
- if not options.no_perfetto:
+ if options.perfetto:
perfetto_process, perfetto_trace_path = perfetto_utils.record_android_trace(
- out_dir, tmp_dir)
+ out_dir, tmp_dir, options.device_id)
# Launch main activity.
launch_activity_result = adb_utils.launch_activity(
@@ -99,7 +105,7 @@
wait_for_activity_to_launch=True)
# Wait for perfetto trace collector to stop.
- if not options.no_perfetto:
+ if options.perfetto:
perfetto_utils.stop_record_android_trace(perfetto_process, out_dir)
# Get minor and major page faults from app process.
@@ -137,36 +143,38 @@
def compute_startup_data(launch_activity_result, perfetto_trace_path, options):
startup_data = {
- 'time_to_activity_started_ms': launch_activity_result.get('total_time')
+ 'adb_startup': launch_activity_result.get('total_time')
}
perfetto_startup_data = {}
- if not options.no_perfetto:
+ if options.perfetto:
trace_processor = TraceProcessor(file_path=perfetto_trace_path)
- # Compute time to first frame according to the builtin android_startup metric.
+ # Compute time to first frame according to the builtin android_startup
+ # metric.
startup_metric = trace_processor.metric(['android_startup'])
time_to_first_frame_ms = \
startup_metric.android_startup.startup[0].to_first_frame.dur_ms
+ perfetto_startup_data['perfetto_startup'] = round(time_to_first_frame_ms)
- # Compute time to first and last doFrame event.
- bind_application_slice = perfetto_utils.find_unique_slice_by_name(
- 'bindApplication', options, trace_processor)
- activity_start_slice = perfetto_utils.find_unique_slice_by_name(
- 'activityStart', options, trace_processor)
- do_frame_slices = perfetto_utils.find_slices_by_name(
- 'Choreographer#doFrame', options, trace_processor)
- first_do_frame_slice = next(do_frame_slices)
- *_, last_do_frame_slice = do_frame_slices
+ if not options.hot_startup:
+ # Compute time to first and last doFrame event.
+ bind_application_slice = perfetto_utils.find_unique_slice_by_name(
+ 'bindApplication', options, trace_processor)
+ activity_start_slice = perfetto_utils.find_unique_slice_by_name(
+ 'activityStart', options, trace_processor)
+ do_frame_slices = perfetto_utils.find_slices_by_name(
+ 'Choreographer#doFrame', options, trace_processor)
+ first_do_frame_slice = next(do_frame_slices)
+ *_, last_do_frame_slice = do_frame_slices
- perfetto_startup_data = {
- 'time_to_first_frame_ms': round(time_to_first_frame_ms),
- 'time_to_first_choreographer_do_frame_ms':
- round(perfetto_utils.get_slice_end_since_start(
- first_do_frame_slice, bind_application_slice)),
- 'time_to_last_choreographer_do_frame_ms':
- round(perfetto_utils.get_slice_end_since_start(
- last_do_frame_slice, bind_application_slice))
- }
+ perfetto_startup_data.update({
+ 'time_to_first_choreographer_do_frame_ms':
+ round(perfetto_utils.get_slice_end_since_start(
+ first_do_frame_slice, bind_application_slice)),
+ 'time_to_last_choreographer_do_frame_ms':
+ round(perfetto_utils.get_slice_end_since_start(
+ last_do_frame_slice, bind_application_slice))
+ })
# Return combined startup data.
return startup_data | perfetto_startup_data
@@ -191,10 +199,6 @@
help='Enable force compilation using profiles',
default=False,
action='store_true')
- result.add_argument('--aot-profile-sleep',
- help='Duration in seconds before forcing compilation',
- default=15,
- type=int)
result.add_argument('--apk',
help='Path to the APK',
required=True)
@@ -202,6 +206,10 @@
help='Device id (e.g., emulator-5554).')
result.add_argument('--device-pin',
help='Device pin code (e.g., 1234)')
+ result.add_argument('--hot-startup',
+ help='Measure hot startup instead of cold startup',
+ default=False,
+ action='store_true')
result.add_argument('--iterations',
help='Number of traces to generate',
default=1,
@@ -216,16 +224,26 @@
result.add_argument('--out-dir',
help='Directory to store trace files in',
required=True)
+ result.add_argument('--baseline-profile',
+ help='Baseline profile to install')
+ result.add_argument('--startup-duration',
+ help='Duration in seconds before shutting down app',
+ default=15,
+ type=int)
options, args = result.parse_known_args(argv)
- assert (not options.aot) or (not options.aot_profile)
+ setattr(options, 'perfetto', not options.no_perfetto)
+ # Profile is only used with --aot.
+ assert options.aot or not options.baseline_profile
return options, args
def main(argv):
(options, args) = parse_options(argv)
with utils.TempDir() as tmp_dir:
+ apk = apk_utils.add_baseline_profile_to_apk(
+ options.apk, options.baseline_profile, tmp_dir)
tear_down_options = adb_utils.prepare_for_interaction_with_device(
options.device_id, options.device_pin)
- run_all(options, tmp_dir)
+ run_all(apk, options, tmp_dir)
adb_utils.tear_down_after_interaction_with_device(
tear_down_options, options.device_id)
diff --git a/tools/startup/perfetto_utils.py b/tools/startup/perfetto_utils.py
index d85f53e..d2f53b4 100644
--- a/tools/startup/perfetto_utils.py
+++ b/tools/startup/perfetto_utils.py
@@ -31,7 +31,7 @@
assert os.path.exists(record_android_trace_path)
return record_android_trace_path
-def record_android_trace(out_dir, tmp_dir):
+def record_android_trace(out_dir, tmp_dir, device_id=None):
record_android_trace_path = ensure_record_android_trace(tmp_dir)
config_path = os.path.join(os.path.dirname(__file__), 'config.pbtx')
perfetto_trace_path = os.path.join(out_dir, 'trace.perfetto-trace')
@@ -43,6 +43,8 @@
'--out',
perfetto_trace_path,
'--no-open']
+ if device_id is not None:
+ cmd.extend(['--serial', device_id])
perfetto_process = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
lines = []
diff --git a/tools/test.py b/tools/test.py
index 665ab5f..0e3bf0f 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -530,7 +530,7 @@
print("Reading failed tests in", report)
failing = set()
inFailedSection = False
- for line in file(report):
+ for line in open(report):
l = line.strip()
if l == "<h2>Failed tests</h2>":
inFailedSection = True
diff --git a/tools/utils.py b/tools/utils.py
index 2a4b18e..9e837c3 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -51,7 +51,6 @@
R8LIB_TESTS_DEPS_TARGET = R8_TESTS_DEPS_TARGET
ALL_DEPS_JAR = os.path.join(LIBS, 'deps_all.jar')
-D8_JAR = os.path.join(LIBS, 'd8.jar')
R8_JAR = os.path.join(LIBS, 'r8.jar')
R8_WITH_RELOCATED_DEPS_JAR = os.path.join(LIBS, 'r8_with_relocated_deps.jar')
R8LIB_JAR = os.path.join(LIBS, 'r8lib.jar')
@@ -102,6 +101,7 @@
USER_HOME = os.path.expanduser('~')
R8_TEST_RESULTS_BUCKET = 'r8-test-results'
+R8_INTERNAL_TEST_RESULTS_BUCKET = 'r8-internal-test-results'
def archive_file(name, gs_dir, src_file):
gs_file = '%s/%s' % (gs_dir, name)
@@ -344,7 +344,9 @@
if is_html:
cmd += ['-z', 'html']
if public_read:
- cmd += ['-a', 'public-read']
+ # TODO(b/177799191) Temporarily disable public-read to test uniform access control
+ if 'r8-test-results' not in destination:
+ cmd += ['-a', 'public-read']
cmd += ['-R', directory, destination]
PrintCmd(cmd)
subprocess.check_call(cmd)
diff --git a/tools/zip_utils.py b/tools/zip_utils.py
new file mode 100644
index 0000000..b0571f2
--- /dev/null
+++ b/tools/zip_utils.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import zipfile
+
+def add_file_to_zip(file, destination, zip_file):
+ with zipfile.ZipFile(zip_file, 'a') as zip:
+ zip.write(file, destination)