Merge commit '4667b25930ebdbe237fc7e161a54f686f1b37815' into dev-release
diff --git a/build.gradle b/build.gradle
index 85e3fc6..ea3f498 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,16 +7,15 @@
import desugaredlibrary.CustomConversionAsmRewriterTask
import net.ltgt.gradle.errorprone.CheckSeverity
import org.gradle.internal.os.OperatingSystem
-import tasks.DownloadDependency
import smali.SmaliTask
+import tasks.DownloadDependency
import tasks.GetJarsFromConfiguration
-import utils.Utils
buildscript {
repositories {
+ google()
mavenCentral()
gradlePluginPortal()
- jcenter()
}
}
@@ -32,8 +31,8 @@
asmVersion = '9.5' // When updating update tools/asmifier.py, build.src and Toolhelper as well.
javassistVersion = '3.29.2-GA'
espressoVersion = '3.0.0'
- fastutilVersion = '7.2.0'
- guavaVersion = '30.1.1-jre'
+ fastutilVersion = '7.2.1'
+ guavaVersion = '31.1-jre'
joptSimpleVersion = '4.6'
gsonVersion = '2.7'
junitVersion = '4.13-beta-2'
@@ -42,7 +41,7 @@
// all kotlin compilations are done in tests.
kotlinVersion = '1.8.0'
kotlinExtMetadataJVMVersion = '0.6.0'
- smaliVersion = '2.2b4'
+ smaliVersion = '3.0.3'
errorproneVersion = '2.18.0'
testngVersion = '6.10'
}
@@ -260,7 +259,7 @@
testCompile "com.google.guava:guava:$guavaVersion"
testCompile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
- testCompile group: 'org.smali', name: 'smali', version: smaliVersion
+ testCompile group: 'com.android.tools.smali', name: 'smali', version: smaliVersion
testCompile files('third_party/jasmin/jasmin-2.4.jar')
testCompile files('third_party/jdwp-tests/apache-harmony-jdwp-tests-host.jar')
testCompile files('third_party/ddmlib/ddmlib.jar')
@@ -1140,7 +1139,7 @@
"Main",
["src/main/keep.txt", generateR8LibKeepRules.outputs.files[0]],
r8NoManifestWithRelocatedDeps,
- r8LibPath,
+ r8LibPath
).dependsOn(generateR8LibKeepRules)
inputs.files r8NoManifestWithRelocatedDeps.outputs.files
outputs.file r8LibPath
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index bfe46c2..85815bd 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -5,16 +5,19 @@
apply plugin: 'idea'
repositories {
+ google()
mavenCentral()
}
ext {
+ guavaVersion = '31.1-jre'
asmVersion = '9.5'
+ smaliVersion = '3.0.3'
}
dependencies {
- implementation group: 'com.google.guava', name: 'guava', version: '30.1.1-jre'
- implementation group: 'org.smali', name: 'smali', version: '2.2b4'
+ implementation group: 'com.google.guava', name: 'guava', version: guavaVersion
+ implementation group: 'com.android.tools.smali', name: 'smali', version: smaliVersion
implementation group: 'org.ow2.asm', name: 'asm', version: asmVersion
implementation group: 'org.ow2.asm', name: 'asm-commons', version: asmVersion
implementation group: 'org.ow2.asm', name: 'asm-tree', version: asmVersion
diff --git a/buildSrc/src/main/java/smali/SmaliTask.java b/buildSrc/src/main/java/smali/SmaliTask.java
index dd4e10c..d35102e 100644
--- a/buildSrc/src/main/java/smali/SmaliTask.java
+++ b/buildSrc/src/main/java/smali/SmaliTask.java
@@ -5,6 +5,8 @@
import static java.util.stream.Collectors.toList;
+import com.android.tools.smali.smali.Smali;
+import com.android.tools.smali.smali.SmaliOptions;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
@@ -20,8 +22,6 @@
import org.gradle.workers.WorkAction;
import org.gradle.workers.WorkParameters;
import org.gradle.workers.WorkerExecutor;
-import org.jf.smali.Smali;
-import org.jf.smali.SmaliOptions;
public class SmaliTask extends DefaultTask {
diff --git a/commonBuildSrc/settings.gradle.kts b/commonBuildSrc/settings.gradle.kts
index b7d4523..75c6675 100644
--- a/commonBuildSrc/settings.gradle.kts
+++ b/commonBuildSrc/settings.gradle.kts
@@ -10,6 +10,7 @@
dependencyResolutionManagement {
repositories {
+ google()
mavenCentral()
gradlePluginPortal()
}
diff --git a/commonBuildSrc/src/main/kotlin/Dependencies.kt b/commonBuildSrc/src/main/kotlin/Dependencies.kt
index c10a576..66e88d1 100644
--- a/commonBuildSrc/src/main/kotlin/Dependencies.kt
+++ b/commonBuildSrc/src/main/kotlin/Dependencies.kt
@@ -35,15 +35,15 @@
}
object Versions {
- const val asmVersion = "9.4"
+ const val asmVersion = "9.5"
const val fastUtilVersion = "7.2.0"
const val gsonVersion = "2.7"
- const val guavaVersion = "30.1.1-jre"
+ const val guavaVersion = "31.1-jre"
const val joptSimpleVersion = "4.6"
const val junitVersion = "4.13-beta-2"
const val kotlinVersion = "1.8.0"
const val kotlinMetadataVersion = "0.6.0"
- const val smaliVersion = "2.2b4"
+ const val smaliVersion = "3.0.3"
const val errorproneVersion = "2.18.0"
}
@@ -60,6 +60,6 @@
"org.jetbrains.kotlinx:kotlinx-metadata-jvm:${Versions.kotlinMetadataVersion}" }
val kotlinStdLib by lazy { "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlinVersion}" }
val kotlinReflect by lazy { "org.jetbrains.kotlin:kotlin-reflect:${Versions.kotlinVersion}" }
- val smali by lazy { "org.smali:smali:${Versions.smaliVersion}" }
+ val smali by lazy { "com.android.tools.smali:smali:${Versions.smaliVersion}" }
val errorprone by lazy { "com.google.errorprone:error_prone_core:${Versions.errorproneVersion}" }
}
diff --git a/compatibility-faq.md b/compatibility-faq.md
index f0d9c05..cb33077 100644
--- a/compatibility-faq.md
+++ b/compatibility-faq.md
@@ -175,6 +175,34 @@
See also https://github.com/square/retrofit/issues/3005 ("Insufficient keep
rules for R8 in full mode").
+### Return type must be parameterized
+
+Consider a service as the following:
+```
+interface Api {
+
+ @GET("<uri>")
+ fun getData(): Observable<Data>
+
+}
+```
+
+Retrofit instantiate a return type by inspecting the generic signature, here
+`Observable` from `io.reactivex.rxjava3.core`. Those classes are not guarded by
+keep rules prior to https://github.com/square/retrofit/pull/3886 so one has to
+manually add keep rules to prevent R8 in full mode stripping the generic
+signature. The proposed rule in https://github.com/square/retrofit/pull/3886 is:
+```
+-if interface * { @retrofit2.http.* public *** *(...); }
+-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
+```
+After https://github.com/square/retrofit/pull/3886 is merged, the above rule
+is automatically included in your build. You can add the rule to your build
+until then.
+
+Note, the `Data` class probably also needs to be kept if used since this is
+also constructed reflectively.
+
### Kotlin suspend functions and generic signatures
For Kotlin suspend functions the generic signature is reflectively read.
diff --git a/src/main/dontwarn.txt b/src/main/dontwarn.txt
index e217663..6706080 100644
--- a/src/main/dontwarn.txt
+++ b/src/main/dontwarn.txt
@@ -1,3 +1,4 @@
# TODO(b/176783536): Avoid need to use -dontwarn.
-dontwarn com.google.errorprone.annotations.**
-dontwarn com.google.j2objc.annotations.*
+-dontwarn javax.annotation.CheckForNull
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
index 03ae2fd..48f5c36 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
@@ -280,8 +280,8 @@
}
/**
- * This method must match the lookup in
- * {@link com.android.tools.r8.JdkClassFileProvider#fromJdkHome}.
+ * This method must match the lookup in {@link
+ * com.android.tools.r8.JdkClassFileProvider#fromJdkHome}.
*/
private static boolean isJdkHome(Path home) {
Path jrtFsJar = home.resolve("lib").resolve("jrt-fs.jar");
@@ -295,10 +295,7 @@
}
// JRE has rt.jar in lib/rt.jar.
rtJar = home.resolve("lib").resolve("rt.jar");
- if (Files.exists(rtJar)) {
- return true;
- }
- return false;
+ return Files.exists(rtJar);
}
static void addLibraryArgument(BaseCommand.Builder builder, Origin origin, String arg) {
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
new file mode 100644
index 0000000..2efea81
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -0,0 +1,90 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8;
+
+import com.android.tools.r8.origin.CommandLineOrigin;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ExceptionUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.SelfRetraceTest;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ThreadUtils;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * The GlobalSyntheticsGenerator, a tool for generating a dex file for all possible global
+ * synthetics.
+ */
+public class GlobalSyntheticsGenerator {
+
+ /**
+ * Main API entry for the global synthetics generator.
+ *
+ * @param command GlobalSyntheticsGenerator command.
+ */
+ public static void run(GlobalSyntheticsGeneratorCommand command)
+ throws CompilationFailedException {
+ runForTesting(command.getInputApp(), command.getInternalOptions());
+ }
+
+ /**
+ * Main API entry for the global synthetics generator.
+ *
+ * @param command GlobalSyntheticsGenerator command.
+ * @param executor executor service from which to get threads for multi-threaded processing.
+ */
+ public static void run(GlobalSyntheticsGeneratorCommand command, ExecutorService executor)
+ throws CompilationFailedException {
+ run(command.getInputApp(), command.getInternalOptions(), executor);
+ }
+
+ static void runForTesting(AndroidApp app, InternalOptions options)
+ throws CompilationFailedException {
+ ExecutorService executorService = ThreadUtils.getExecutorService(options);
+ run(app, options, executorService);
+ }
+
+ private static void run(AndroidApp app, InternalOptions options, ExecutorService executorService)
+ throws CompilationFailedException {
+ try {
+ ExceptionUtils.withD8CompilationHandler(
+ options.reporter,
+ () -> {
+ throw new RuntimeException("Implement GlobalSyntheticsGenerator");
+ });
+ } finally {
+ executorService.shutdown();
+ }
+ }
+
+ private static void run(String[] args) throws CompilationFailedException {
+ GlobalSyntheticsGeneratorCommand command =
+ GlobalSyntheticsGeneratorCommand.parse(args, CommandLineOrigin.INSTANCE).build();
+ if (command.isPrintHelp()) {
+ SelfRetraceTest.test();
+ System.out.println(GlobalSyntheticsGeneratorCommandParser.getUsageMessage());
+ return;
+ }
+ if (command.isPrintVersion()) {
+ System.out.println("GlobalSynthetics " + Version.getVersionString());
+ return;
+ }
+ run(command);
+ }
+
+ /**
+ * Command-line entry to GlobalSynthetics.
+ *
+ * <p>See {@link GlobalSyntheticsGeneratorCommandParser#getUsageMessage()} or run {@code
+ * globalsynthetics --help} for usage information.
+ */
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ throw new RuntimeException(
+ StringUtils.joinLines(
+ "Invalid invocation.", GlobalSyntheticsGeneratorCommandParser.getUsageMessage()));
+ }
+ ExceptionUtils.withMainProgramHandler(() -> run(args));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
new file mode 100644
index 0000000..2187b67
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
@@ -0,0 +1,260 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8;
+
+import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.StringDiagnostic;
+import java.nio.file.Path;
+import java.util.Collection;
+
+/**
+ * Immutable command structure for an invocation of the {@link GlobalSyntheticsGenerator} compiler.
+ */
+public final class GlobalSyntheticsGeneratorCommand extends BaseCommand {
+
+ private final ProgramConsumer programConsumer;
+ private final StringConsumer classNameConsumer;
+ private final Reporter reporter;
+ private final int minApiLevel;
+
+ private final DexItemFactory factory = new DexItemFactory();
+
+ private GlobalSyntheticsGeneratorCommand(
+ AndroidApp androidApp,
+ ProgramConsumer programConsumer,
+ StringConsumer ClassNameConsumer,
+ Reporter reporter,
+ int minApiLevel) {
+ super(androidApp);
+ this.programConsumer = programConsumer;
+ this.classNameConsumer = ClassNameConsumer;
+ this.minApiLevel = minApiLevel;
+ this.reporter = reporter;
+ }
+
+ private GlobalSyntheticsGeneratorCommand(boolean printHelp, boolean printVersion) {
+ super(printHelp, printVersion);
+ this.programConsumer = null;
+ this.classNameConsumer = null;
+ this.minApiLevel = AndroidApiLevel.B.getLevel();
+
+ reporter = new Reporter();
+ }
+
+ /**
+ * Parse the GlobalSyntheticsGenerator command-line.
+ *
+ * <p>Parsing will set the supplied options or their default value if they have any.
+ *
+ * @param args Command-line arguments array.
+ * @param origin Origin description of the command-line arguments.
+ * @return GlobalSyntheticsGenerator command builder with state according to parsed command line.
+ */
+ public static Builder parse(String[] args, Origin origin) {
+ return GlobalSyntheticsGeneratorCommandParser.parse(args, origin);
+ }
+
+ /**
+ * Parse the GlobalSyntheticsGenerator command-line.
+ *
+ * <p>Parsing will set the supplied options or their default value if they have any.
+ *
+ * @param args Command-line arguments array.
+ * @param origin Origin description of the command-line arguments.
+ * @param handler Custom defined diagnostics handler.
+ * @return GlobalSyntheticsGenerator command builder with state according to parsed command line.
+ */
+ public static Builder parse(String[] args, Origin origin, DiagnosticsHandler handler) {
+ return GlobalSyntheticsGeneratorCommandParser.parse(args, origin, handler);
+ }
+
+ protected static class DefaultR8DiagnosticsHandler implements DiagnosticsHandler {
+
+ @Override
+ public void error(Diagnostic error) {
+ if (error instanceof DexFileOverflowDiagnostic) {
+ DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error;
+ DiagnosticsHandler.super.error(
+ new StringDiagnostic(
+ overflowDiagnostic.getDiagnosticMessage()
+ + ". Library too large. GlobalSyntheticsGenerator can only produce a single"
+ + " .dex file"));
+ return;
+ }
+ DiagnosticsHandler.super.error(error);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Builder builder(DiagnosticsHandler diagnosticsHandler) {
+ return new Builder(diagnosticsHandler);
+ }
+
+ @Override
+ InternalOptions getInternalOptions() {
+ InternalOptions internal = new InternalOptions(factory, reporter);
+ assert !internal.debug;
+ assert !internal.minimalMainDex;
+ internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(minApiLevel));
+ assert !internal.intermediate;
+ assert internal.retainCompileTimeAnnotations;
+ internal.programConsumer = programConsumer;
+
+ // Assert and fixup defaults.
+ assert !internal.isShrinking();
+ assert !internal.isMinifying();
+ assert !internal.passthroughDexCode;
+
+ return internal;
+ }
+
+ /**
+ * Builder for constructing a GlobalSyntheticsGeneratorCommand.
+ *
+ * <p>A builder is obtained by calling {@link GlobalSyntheticsGeneratorCommand#builder}.
+ */
+ public static class Builder
+ extends BaseCommand.Builder<GlobalSyntheticsGeneratorCommand, Builder> {
+
+ private ProgramConsumer programConsumer = null;
+ private StringConsumer globalSyntheticClassesListConsumer = null;
+ private Reporter reporter;
+ private int minApiLevel = AndroidApiLevel.B.getLevel();
+
+ private Builder() {
+ this(new DefaultR8DiagnosticsHandler());
+ }
+
+ private Builder(DiagnosticsHandler diagnosticsHandler) {
+ this.reporter = new Reporter(diagnosticsHandler);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+
+ public Builder setReporter(Reporter reporter) {
+ this.reporter = reporter;
+ return self();
+ }
+
+ public Builder setMinApiLevel(int minApiLevel) {
+ this.minApiLevel = minApiLevel;
+ return self();
+ }
+
+ @Override
+ void validate() {
+ if (isPrintHelp() || isPrintVersion()) {
+ return;
+ }
+ if (!(programConsumer instanceof DexIndexedConsumer)) {
+ reporter.error("G8 does not support compiling to dex per class or class files");
+ }
+ }
+
+ @Override
+ public GlobalSyntheticsGeneratorCommand makeCommand() {
+ if (isPrintHelp() || isPrintVersion()) {
+ return new GlobalSyntheticsGeneratorCommand(isPrintHelp(), isPrintVersion());
+ }
+ validate();
+ return new GlobalSyntheticsGeneratorCommand(
+ getAppBuilder().build(),
+ programConsumer,
+ globalSyntheticClassesListConsumer,
+ reporter,
+ minApiLevel);
+ }
+
+ public Builder setGlobalSyntheticClassesListOutput(Path path) {
+ return setGlobalSyntheticClassesListConsumer(new StringConsumer.FileConsumer(path));
+ }
+
+ public Builder setGlobalSyntheticClassesListConsumer(
+ StringConsumer globalSyntheticClassesListOutput) {
+ this.globalSyntheticClassesListConsumer = globalSyntheticClassesListOutput;
+ return self();
+ }
+
+ public Builder setProgramConsumerOutput(Path path) {
+ return setProgramConsumer(
+ FileUtils.isArchive(path)
+ ? new DexIndexedConsumer.ArchiveConsumer(path, false)
+ : new DexIndexedConsumer.DirectoryConsumer(path, false));
+ }
+
+ public Builder setProgramConsumer(ProgramConsumer programConsumer) {
+ this.programConsumer = programConsumer;
+ return self();
+ }
+
+ @Override
+ public Builder addProgramFiles(Collection<Path> files) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addProgramResourceProvider(ProgramResourceProvider programProvider) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addClasspathFiles(Path... files) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addClasspathFiles(Collection<Path> files) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addClasspathResourceProvider(ClassFileResourceProvider provider) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addClassProgramData(byte[] data, Origin origin) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ Builder addDexProgramData(byte[] data, Origin origin) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addMainDexListFiles(Path... files) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addMainDexListFiles(Collection<Path> files) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addMainDexClasses(String... classes) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+
+ @Override
+ public Builder addMainDexClasses(Collection<String> classes) {
+ throw new Unreachable("Should not be used for global synthetics generation");
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParser.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParser.java
new file mode 100644
index 0000000..36e5bbd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParser.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8;
+
+import static com.android.tools.r8.BaseCompilerCommandParser.parsePositiveIntArgument;
+
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.FlagFile;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Set;
+
+public class GlobalSyntheticsGeneratorCommandParser {
+
+ private static final String LOWER_CASE_NAME = "globalsynthetics";
+ private static final String MIN_API_FLAG = "--min-api";
+
+ private static final String USAGE_MESSAGE =
+ StringUtils.lines("Usage: " + LOWER_CASE_NAME + " [options] " + "where options are:");
+
+ public static List<ParseFlagInfo> getFlags() {
+ return ImmutableList.<ParseFlagInfo>builder()
+ .add(ParseFlagInfoImpl.getMinApi())
+ .add(ParseFlagInfoImpl.getLib())
+ .add(ParseFlagInfoImpl.flag1("--output", "<dex-file>", "Output result in <dex-file>."))
+ .add(
+ ParseFlagInfoImpl.flag1(
+ "--classes-list-output", "<file>", "Output list of generated classes in <file>"))
+ .add(ParseFlagInfoImpl.getVersion(LOWER_CASE_NAME))
+ .add(ParseFlagInfoImpl.getHelp())
+ .build();
+ }
+
+ static String getUsageMessage() {
+ StringBuilder builder = new StringBuilder();
+ StringUtils.appendLines(builder, USAGE_MESSAGE);
+ new ParseFlagPrinter().addFlags(getFlags()).appendLinesToBuilder(builder);
+ return builder.toString();
+ }
+
+ private static final Set<String> OPTIONS_WITH_ONE_PARAMETER =
+ ImmutableSet.of("--output", "--lib", MIN_API_FLAG, "---classes-list-output");
+
+ public static GlobalSyntheticsGeneratorCommand.Builder parse(String[] args, Origin origin) {
+ return new GlobalSyntheticsGeneratorCommandParser()
+ .parse(args, origin, GlobalSyntheticsGeneratorCommand.builder());
+ }
+
+ public static GlobalSyntheticsGeneratorCommand.Builder parse(
+ String[] args, Origin origin, DiagnosticsHandler handler) {
+ return new GlobalSyntheticsGeneratorCommandParser()
+ .parse(args, origin, GlobalSyntheticsGeneratorCommand.builder(handler));
+ }
+
+ private GlobalSyntheticsGeneratorCommand.Builder parse(
+ String[] args, Origin origin, GlobalSyntheticsGeneratorCommand.Builder builder) {
+ Path outputPath = null;
+ boolean hasDefinedApiLevel = false;
+ String[] expandedArgs = FlagFile.expandFlagFiles(args, builder::error);
+ for (int i = 0; i < expandedArgs.length; i++) {
+ String arg = expandedArgs[i].trim();
+ String nextArg = null;
+ if (OPTIONS_WITH_ONE_PARAMETER.contains(arg)) {
+ if (++i < expandedArgs.length) {
+ nextArg = expandedArgs[i];
+ } else {
+ builder.error(
+ new StringDiagnostic("Missing parameter for " + expandedArgs[i - 1] + ".", origin));
+ break;
+ }
+ }
+ if (arg.length() == 0) {
+ continue;
+ } else if (arg.equals("--help")) {
+ builder.setPrintHelp(true);
+ } else if (arg.equals("--version")) {
+ builder.setPrintVersion(true);
+ } else if (arg.equals("--output")) {
+ if (outputPath != null) {
+ builder.error(
+ new StringDiagnostic(
+ "Cannot output both to '" + outputPath + "' and '" + nextArg + "'", origin));
+ continue;
+ }
+ outputPath = Paths.get(nextArg);
+ } else if (arg.equals(MIN_API_FLAG)) {
+ if (hasDefinedApiLevel) {
+ builder.error(
+ new StringDiagnostic("Cannot set multiple " + MIN_API_FLAG + " options", origin));
+ } else {
+ parsePositiveIntArgument(
+ builder::error, MIN_API_FLAG, nextArg, origin, builder::setMinApiLevel);
+ hasDefinedApiLevel = true;
+ }
+ } else if (arg.equals("--lib")) {
+ builder.addLibraryFiles(Paths.get(nextArg));
+ } else if (arg.equals("--classes-list-output")) {
+ builder.setGlobalSyntheticClassesListOutput(Paths.get(nextArg));
+ } else if (arg.startsWith("--")) {
+ builder.error(new StringDiagnostic("Unknown option: " + arg, origin));
+ }
+ }
+ if (outputPath == null) {
+ outputPath = Paths.get(".");
+ }
+ return builder.setProgramConsumerOutput(outputPath);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/JarSizeCompare.java b/src/main/java/com/android/tools/r8/JarSizeCompare.java
index 6f80def..0be3461 100644
--- a/src/main/java/com/android/tools/r8/JarSizeCompare.java
+++ b/src/main/java/com/android/tools/r8/JarSizeCompare.java
@@ -21,7 +21,6 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
-import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -119,8 +118,8 @@
}
}
for (Entry<String, Map<String, InputClass[]>> library : byLibrary(inputClasses)) {
- System.out.println("");
- System.out.println(Strings.repeat("=", 100));
+ System.out.println();
+ System.out.println("=".repeat(100));
String commonPrefix = getCommonPrefix(library.getValue().keySet());
if (library.getKey().isEmpty()) {
System.out.println("PROGRAM (" + commonPrefix + ")");
diff --git a/src/main/java/com/android/tools/r8/ParseFlagPrinter.java b/src/main/java/com/android/tools/r8/ParseFlagPrinter.java
index a14556e..3f30806 100644
--- a/src/main/java/com/android/tools/r8/ParseFlagPrinter.java
+++ b/src/main/java/com/android/tools/r8/ParseFlagPrinter.java
@@ -4,7 +4,6 @@
package com.android.tools.r8;
import com.android.tools.r8.utils.StringUtils;
-import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.List;
@@ -101,7 +100,7 @@
/** Convenience method to set the prefix to be 'indent' number of spaces. */
public ParseFlagPrinter setIndent(int indent) {
- return setPrefix(Strings.repeat(" ", indent));
+ return setPrefix(" ".repeat(indent));
}
/**
diff --git a/src/main/java/com/android/tools/r8/dump/DumpOptions.java b/src/main/java/com/android/tools/r8/dump/DumpOptions.java
index 9779fcf..ae0ecd8 100644
--- a/src/main/java/com/android/tools/r8/dump/DumpOptions.java
+++ b/src/main/java/com/android/tools/r8/dump/DumpOptions.java
@@ -203,6 +203,9 @@
case BACKEND_KEY:
builder.setBackend(Backend.valueOf(value));
return;
+ case ENABLE_MISSING_LIBRARY_API_MODELING:
+ builder.setEnableMissingLibraryApiModeling(Boolean.parseBoolean(value));
+ return;
case TOOL_KEY:
builder.setTool(Tool.valueOf(value));
return;
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
index 53ebcee..90faadc 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.contexts.CompilationContext;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
import com.android.tools.r8.ir.conversion.OneTimeMethodProcessor;
@@ -78,6 +79,10 @@
ps.println("# Bytecode for");
ps.println("# Class: '" + clazzName + "'");
if (writeAllClassInfo) {
+ ClassSignature signature = clazz.getClassSignature();
+ if (signature != null && signature.hasSignature()) {
+ ps.println("# Signature: " + signature);
+ }
writeAnnotations(clazz, clazz.annotations(), ps);
ps.println("# Flags: '" + clazz.accessFlags + "'");
if (clazz.superType != application.dexItemFactory.objectType) {
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 4df769b..165878d 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -49,7 +49,6 @@
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralMapping;
-import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
@@ -880,7 +879,7 @@
if (existingThisIndex < 0) {
return;
}
- String fakeThisName = Strings.repeat(FAKE_THIS_PREFIX, largestPrefix + 1) + FAKE_THIS_SUFFIX;
+ String fakeThisName = FAKE_THIS_PREFIX.repeat(largestPrefix + 1) + FAKE_THIS_SUFFIX;
DebugLocalInfo debugLocalInfo =
new DebugLocalInfo(factory.createString(fakeThisName), this.originalHolder, null);
LocalVariableInfo thisLocalInfo = localVariables.get(existingThisIndex);
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 4cb2a24..ae96c5e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -48,7 +48,6 @@
import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
-import com.google.common.base.Strings;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import java.nio.ShortBuffer;
import java.util.ArrayList;
@@ -304,7 +303,7 @@
}
}
- String fakeThisName = Strings.repeat(FAKE_THIS_PREFIX, largestPrefix + 1) + FAKE_THIS_SUFFIX;
+ String fakeThisName = FAKE_THIS_PREFIX.repeat(largestPrefix + 1) + FAKE_THIS_SUFFIX;
DexString[] parameters = eventBasedInfo.parameters;
DexString[] newParameters = new DexString[parameters.length + 1];
newParameters[0] = factory.createString(fakeThisName);
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index ae3f0ac..164797a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -41,7 +41,6 @@
import com.android.tools.r8.utils.LRUCacheTable;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
-import com.google.common.base.Strings;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
@@ -2932,7 +2931,7 @@
public DexType createArrayType(int nesting, DexType baseType) {
assert nesting > 0;
- return createType(Strings.repeat("[", nesting) + baseType.toDescriptorString());
+ return createType("[".repeat(nesting) + baseType.toDescriptorString());
}
public DexField createField(DexType clazz, DexType type, DexString name) {
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignature.java b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
index 920fbc1..f1122b8 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -259,6 +259,9 @@
}
public ClassSignature visit(GenericSignatureVisitor visitor) {
+ if (hasNoSignature()) {
+ return this;
+ }
List<FormalTypeParameter> rewrittenParameters =
visitor.visitFormalTypeParameters(formalTypeParameters);
ClassTypeSignature rewrittenSuperClass = visitor.visitSuperClass(superClassSignature);
@@ -291,10 +294,6 @@
return NO_CLASS_SIGNATURE;
}
- public ClassSignature toObjectBoundWithSameFormals(ClassTypeSignature objectBound) {
- return new ClassSignature(formalTypeParameters, objectBound, getEmptySuperInterfaces());
- }
-
public List<FieldTypeSignature> getGenericArgumentsToSuperType(DexType type) {
assert hasSignature();
if (superClassSignature.type == type) {
@@ -314,9 +313,9 @@
public static class ClassSignatureBuilder {
- private List<FormalTypeParameter> formalTypeParameters = new ArrayList<>();
+ private final List<FormalTypeParameter> formalTypeParameters = new ArrayList<>();
private ClassTypeSignature superClassSignature = null;
- private List<ClassTypeSignature> superInterfaceSignatures = new ArrayList<>();
+ private final List<ClassTypeSignature> superInterfaceSignatures = new ArrayList<>();
private ClassSignatureBuilder() {}
@@ -336,9 +335,8 @@
}
public ClassSignature build() {
- ClassSignature classSignature =
- new ClassSignature(formalTypeParameters, superClassSignature, superInterfaceSignatures);
- return classSignature;
+ return new ClassSignature(
+ formalTypeParameters, superClassSignature, superInterfaceSignatures);
}
}
}
@@ -628,6 +626,9 @@
}
public ClassTypeSignature visit(GenericSignatureVisitor visitor) {
+ if (hasNoSignature()) {
+ return this;
+ }
DexType visitedType = visitor.visitType(type);
if (visitedType == null) {
return null;
@@ -855,6 +856,9 @@
}
public MethodTypeSignature visit(GenericSignatureVisitor visitor) {
+ if (hasNoSignature()) {
+ return this;
+ }
List<FormalTypeParameter> rewrittenParameters =
visitor.visitFormalTypeParameters(formalTypeParameters);
List<TypeSignature> rewrittenSignatures = visitor.visitMethodTypeSignatures(typeSignatures);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 31037b9..422dc72 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
import com.android.tools.r8.graph.InvalidCode;
import com.android.tools.r8.graph.MethodCollection;
import com.android.tools.r8.graph.ProgramMethod;
@@ -139,14 +138,7 @@
kinds -> kinds.COMPANION_CLASS,
iface,
appView,
- builder ->
- builder
- .setSourceFile(iface.sourceFile)
- .setGenericSignature(
- iface
- .getClassSignature()
- .toObjectBoundWithSameFormals(
- new ClassTypeSignature(appView.dexItemFactory().objectType))),
+ builder -> builder.setSourceFile(iface.sourceFile),
methodBuilderCallback,
newMethodCallback);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 03245b3..05c83da 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
@@ -47,6 +46,7 @@
import com.android.tools.r8.shaking.AssumeInfoCollection;
import com.android.tools.r8.shaking.MainDexInfo;
import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.InlinerOptions;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -57,6 +57,7 @@
public final class DefaultInliningOracle implements InliningOracle, InliningStrategy {
private final AppView<AppInfoWithLiveness> appView;
+ private final InternalOptions options;
private final InlinerOptions inlinerOptions;
private final MainDexInfo mainDexInfo;
private final ProgramMethod method;
@@ -71,7 +72,8 @@
MethodProcessor methodProcessor,
int inliningInstructionAllowance) {
this.appView = appView;
- this.inlinerOptions = appView.options().inlinerOptions();
+ this.options = appView.options();
+ this.inlinerOptions = options.inlinerOptions();
this.reasonStrategy = inliningReasonStrategy;
this.mainDexInfo = appView.appInfo().getMainDexInfo();
this.method = method;
@@ -132,15 +134,14 @@
// Do not inline if the inlinee is greater than the api caller level.
// TODO(b/188498051): We should not force inline lower api method calls.
if (reason != Reason.FORCE
- && !isApiSafeForInlining(
- method, singleTarget, appView.options(), whyAreYouNotInliningReporter)) {
+ && !isApiSafeForInlining(method, singleTarget, options, whyAreYouNotInliningReporter)) {
return false;
}
// We don't inline into constructors when producing class files since this can mess up
// the stackmap, see b/136250031
if (method.getDefinition().isInstanceInitializer()
- && appView.options().isGeneratingClassFiles()
+ && options.isGeneratingClassFiles()
&& reason != Reason.FORCE) {
whyAreYouNotInliningReporter.reportNoInliningIntoConstructorsWhenGeneratingClassFiles();
return false;
@@ -205,19 +206,15 @@
}
private boolean canHaveIssuesWithMonitors(ProgramMethod singleTarget, ProgramMethod context) {
- if (appView.options().canHaveIssueWithInlinedMonitors()) {
- if (hasMonitorsOrIsSynchronized(singleTarget.getDefinition())) {
- if (context.getOptimizationInfo().forceInline()
- || hasMonitorsOrIsSynchronized(context.getDefinition())) {
- return true;
- }
- }
+ if (options.canHaveIssueWithInlinedMonitors() && hasMonitorsOrIsSynchronized(singleTarget)) {
+ return context.getOptimizationInfo().forceInline() || hasMonitorsOrIsSynchronized(context);
}
return false;
}
- public static boolean hasMonitorsOrIsSynchronized(DexEncodedMethod definition) {
- return definition.isSynchronized() || definition.getCode().hasMonitorInstructions();
+ public static boolean hasMonitorsOrIsSynchronized(ProgramMethod method) {
+ return method.getAccessFlags().isSynchronized()
+ || method.getDefinition().getCode().hasMonitorInstructions();
}
public boolean satisfiesRequirementsForSimpleInlining(InvokeMethod invoke, ProgramMethod target) {
@@ -257,9 +254,7 @@
}
}
}
- if (appView.options().isGeneratingDex()
- && invoke.hasOutValue()
- && invoke.outValue().hasNonDebugUsers()) {
+ if (options.isGeneratingDex() && invoke.hasOutValue() && invoke.outValue().hasNonDebugUsers()) {
assert DexMoveResult.SIZE == DexMoveResultObject.SIZE;
assert DexMoveResult.SIZE == DexMoveResultWide.SIZE;
instructionLimit += DexMoveResult.SIZE;
@@ -327,10 +322,9 @@
// Ensure that we don't introduce several monitors in the same method on old device that can
// choke on this. If a context is forceinline, e.g., from class merging, don't ever inline
// monitors, since that may conflict with a similar other constructor.
- if (appView.options().canHaveIssueWithInlinedMonitors()) {
- if (hasMonitorsOrIsSynchronized(singleTarget.getDefinition())
- && (context.getOptimizationInfo().forceInline()
- || code.metadata().mayHaveMonitorInstruction())) {
+ if (options.canHaveIssueWithInlinedMonitors() && hasMonitorsOrIsSynchronized(singleTarget)) {
+ if (context.getOptimizationInfo().forceInline()
+ || code.metadata().mayHaveMonitorInstruction()) {
return null;
}
}
@@ -366,7 +360,7 @@
ProgramMethod singleTarget,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
DexMethod singleTargetReference = singleTarget.getReference();
- if (!appView.getKeepInfo(singleTarget).isInliningAllowed(appView.options())) {
+ if (!appView.getKeepInfo(singleTarget).isInliningAllowed(options)) {
whyAreYouNotInliningReporter.reportPinned();
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java
index 69a5179..742750d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java
@@ -108,6 +108,10 @@
return mapping.get(unboxedEnumValue);
}
+ public ImmutableInt2ReferenceSortedMap<AbstractValue> getMapping() {
+ return mapping;
+ }
+
public void forEach(BiConsumer<? super Integer, ? super AbstractValue> consumer) {
mapping.forEach(consumer);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 183243b..6b8b450 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -69,8 +69,8 @@
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
-import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
@@ -739,7 +739,7 @@
fixupProto(factory.prependHolderToProto(representative.getReference())),
localUtilityClass.getType(),
newMethodSignature -> !localUtilityMethods.containsKey(newMethodSignature));
- Int2ObjectSortedMap<DexMethod> methodMap = new Int2ObjectLinkedOpenHashMap<>();
+ Int2ReferenceSortedMap<DexMethod> methodMap = new Int2ReferenceLinkedOpenHashMap<>();
IdentityHashMap<DexType, DexMethod> typeToMethod = new IdentityHashMap<>();
map.forEach(
(methodReference, newMethodReference) ->
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index 755f207..abff1ff 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfIf;
-import com.android.tools.r8.cf.code.CfIfCmp;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLabel;
@@ -21,6 +20,8 @@
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
import com.android.tools.r8.cf.code.CfStaticFieldRead;
import com.android.tools.r8.cf.code.CfStaticFieldWrite;
+import com.android.tools.r8.cf.code.CfSwitch;
+import com.android.tools.r8.cf.code.CfSwitch.Kind;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.errors.Unreachable;
@@ -36,9 +37,12 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.optimize.enums.EnumDataMap.EnumData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldMappingData;
-import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
+import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.BooleanUtils;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.BiConsumer;
import org.objectweb.asm.Opcodes;
public abstract class EnumUnboxingCfCodeProvider extends SyntheticCfCodeProvider {
@@ -68,17 +72,66 @@
}
}
+ <T> void addCfSwitch(
+ List<CfInstruction> instructions,
+ BiConsumer<List<CfInstruction>, T> generateCase,
+ Int2ReferenceSortedMap<T> cases,
+ T defaultCase,
+ CfFrame.Builder frameBuilder,
+ boolean defaultThrows) {
+ // The switch is *always* going to be converted to IR then either to dex or back to cf. The IR
+ // representation does not differentiate table and look-up switches, and generates the most
+ // appropriate one in the back-end.
+ // The keys should however be sorted in natural order for packing to table switch to be
+ // generated, which should be implicitly the case with the Int2ObjectSortedMap.
+ assert defaultCase == null || !defaultThrows;
+ boolean hasDefaultCase = defaultCase != null || defaultThrows;
+ assert cases.size() + BooleanUtils.intValue(hasDefaultCase) >= 2;
+ int[] keys = new int[cases.size() - BooleanUtils.intValue(!hasDefaultCase)];
+ List<CfLabel> targets = new ArrayList<>(keys.length);
+ int index = 0;
+ for (int key : cases.keySet()) {
+ if (index < keys.length) {
+ keys[index++] = key;
+ targets.add(new CfLabel());
+ }
+ }
+ CfLabel defaultLabel = new CfLabel();
+ T actualDefaultCase = hasDefaultCase ? defaultCase : cases.get(cases.lastIntKey());
+ assert ArrayUtils.isSorted(keys);
+ assert keys.length == targets.size();
+ // We expect the value to switch on to be in local slot 0.
+ instructions.add(new CfLoad(ValueType.fromDexType(appView.dexItemFactory().intType), 0));
+ instructions.add(new CfSwitch(Kind.LOOKUP, defaultLabel, keys, targets));
+ for (int i = 0; i < keys.length; i++) {
+ instructions.add(targets.get(i));
+ instructions.add(frameBuilder.build());
+ generateCase.accept(instructions, cases.get(keys[i]));
+ assert instructions.get(instructions.size() - 1).isReturn();
+ }
+ instructions.add(defaultLabel);
+ instructions.add(frameBuilder.build());
+ if (defaultThrows) {
+ // default: throw null;
+ instructions.add(new CfConstNull());
+ instructions.add(new CfThrow());
+ } else {
+ generateCase.accept(instructions, actualDefaultCase);
+ assert instructions.get(instructions.size() - 1).isReturn();
+ }
+ }
+
public static class EnumUnboxingMethodDispatchCfCodeProvider extends EnumUnboxingCfCodeProvider {
private final GraphLens codeLens;
private final DexMethod superEnumMethod;
- private final Int2ObjectSortedMap<DexMethod> methodMap;
+ private final Int2ReferenceSortedMap<DexMethod> methodMap;
public EnumUnboxingMethodDispatchCfCodeProvider(
AppView<?> appView,
DexType holder,
DexMethod superEnumMethod,
- Int2ObjectSortedMap<DexMethod> methodMap) {
+ Int2ReferenceSortedMap<DexMethod> methodMap) {
super(appView, holder);
this.codeLens = appView.codeLens();
this.superEnumMethod = superEnumMethod;
@@ -87,45 +140,15 @@
@Override
public CfCodeWithLens generateCfCode() {
- // TODO(b/167942775): Should use a table-switch for large enums (maybe same threshold in the
- // rewriter of switchmaps).
-
assert !methodMap.isEmpty();
- DexItemFactory factory = appView.dexItemFactory();
- boolean hasDefaultCase = superEnumMethod != null;
+ List<CfInstruction> instructions = new ArrayList<>();
DexMethod representative = methodMap.values().iterator().next();
-
- int invokeSize = representative.getParameters().size() + 2;
- int branchSize = 5;
- int instructionsSize =
- methodMap.size() * (invokeSize + branchSize)
- + (hasDefaultCase ? invokeSize : -branchSize);
- List<CfInstruction> instructions = new ArrayList<>(instructionsSize);
-
CfFrame.Builder frameBuilder = CfFrame.builder();
for (DexType parameter : representative.getParameters()) {
frameBuilder.appendLocal(FrameType.initialized(parameter));
}
- methodMap.forEach(
- (unboxedEnumValue, method) -> {
- boolean lastCase = methodMap.lastIntKey() == unboxedEnumValue && !hasDefaultCase;
- if (!lastCase) {
- CfLabel dest = new CfLabel();
- instructions.add(new CfLoad(ValueType.fromDexType(factory.intType), 0));
- instructions.add(new CfConstNumber(unboxedEnumValue, ValueType.INT));
- instructions.add(new CfIfCmp(IfType.NE, ValueType.INT, dest));
- addReturnInvoke(instructions, method);
- instructions.add(dest);
- instructions.add(frameBuilder.build());
- } else {
- addReturnInvoke(instructions, method);
- }
- });
-
- if (hasDefaultCase) {
- addReturnInvoke(instructions, superEnumMethod);
- }
- assert instructions.size() == instructionsSize;
+ addCfSwitch(
+ instructions, this::addReturnInvoke, methodMap, superEnumMethod, frameBuilder, false);
return new CfCodeWithLens(getHolder(), defaultMaxStack(), defaultMaxLocals(), instructions);
}
@@ -187,44 +210,32 @@
@Override
public CfCode generateCfCode() {
- // TODO(b/167942775): Should use a table-switch for large enums (maybe same threshold in the
- // rewriter of switchmaps).
// Generated static method, for class com.x.MyEnum {A(10),B(20);} would look like:
// String UtilityClass#com.x.MyEnum_toString(int i) {
- // if (i == 1) { return 10;}
- // if (i == 2) { return 20;}
- // throw null;
+ // switch (i) {
+ // case 1: return 10;
+ // case 2: return 20;
+ // default: throw null; // or throw default value.
+ // }
+ // }
DexItemFactory factory = appView.dexItemFactory();
List<CfInstruction> instructions = new ArrayList<>();
-
- // if (i == 1) { return 10;}
- // if (i == 2) { return 20;}
CfFrame.Builder frameBuilder =
CfFrame.builder().appendLocal(FrameType.initialized(factory.intType));
- fieldDataMap.forEach(
- (unboxedEnumValue, value) -> {
- CfLabel dest = new CfLabel();
- instructions.add(new CfLoad(ValueType.fromDexType(factory.intType), 0));
- instructions.add(new CfConstNumber(unboxedEnumValue, ValueType.INT));
- instructions.add(new CfIfCmp(IfType.NE, ValueType.INT, dest));
- addCfInstructionsForAbstractValue(instructions, value, returnType);
- instructions.add(new CfReturn(ValueType.fromDexType(returnType)));
- instructions.add(dest);
- instructions.add(frameBuilder.build());
- });
-
- if (nullValue != null) {
- // return "null"
- addCfInstructionsForAbstractValue(instructions, nullValue, returnType);
- instructions.add(new CfReturn(ValueType.fromDexType(returnType)));
- } else {
- // throw null;
- instructions.add(new CfConstNull());
- instructions.add(new CfThrow());
- }
-
+ addCfSwitch(
+ instructions,
+ this::addReturnValue,
+ fieldDataMap.getMapping(),
+ nullValue,
+ frameBuilder,
+ nullValue == null);
return standardCfCodeFromInstructions(instructions);
}
+
+ private void addReturnValue(List<CfInstruction> instructions, AbstractValue value) {
+ addCfInstructionsForAbstractValue(instructions, value, returnType);
+ instructions.add(new CfReturn(ValueType.fromDexType(returnType)));
+ }
}
public static class EnumUnboxingValueOfCfCodeProvider extends EnumUnboxingCfCodeProvider {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
index 67a900a..bece7b9 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -21,7 +21,6 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.TriFunction;
-import com.google.common.base.Strings;
import java.util.List;
import java.util.function.Consumer;
import kotlin.Metadata;
@@ -106,9 +105,7 @@
JvmMethodSignature methodSignature, int intArguments) {
return new JvmMethodSignature(
methodSignature.getName() + "$default",
- methodSignature
- .getDesc()
- .replace(")", Strings.repeat("I", intArguments) + "Ljava/lang/Object;)"));
+ methodSignature.getDesc().replace(")", "I".repeat(intArguments) + "Ljava/lang/Object;)"));
}
static class KmPropertyProcessor {
diff --git a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/ClassNameComputationInfo.java b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/ClassNameComputationInfo.java
index 68f97d9..59e398c 100644
--- a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/ClassNameComputationInfo.java
+++ b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/ClassNameComputationInfo.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.NamingLens;
-import com.google.common.base.Strings;
public class ClassNameComputationInfo extends NameComputationInfo<DexType> {
@@ -45,7 +44,7 @@
case NAME:
name = getClassNameFromDescriptor(descriptor);
if (arrayDepth > 0) {
- name = Strings.repeat("[", arrayDepth) + "L" + name + ";";
+ name = "[".repeat(arrayDepth) + "L" + name + ";";
}
break;
@@ -60,7 +59,7 @@
case CANONICAL_NAME:
name = getCanonicalNameFromDescriptor(descriptor);
if (arrayDepth > 0) {
- name = name + Strings.repeat("[]", arrayDepth);
+ name = name + "[]".repeat(arrayDepth);
}
break;
@@ -74,7 +73,7 @@
name = getUnqualifiedClassNameFromDescriptor(descriptor);
}
if (arrayDepth > 0) {
- name = name + Strings.repeat("[]", arrayDepth);
+ name = name + "[]".repeat(arrayDepth);
}
break;
diff --git a/src/main/java/com/android/tools/r8/retrace/Partition.java b/src/main/java/com/android/tools/r8/retrace/Partition.java
index c7b942f..1582b5e 100644
--- a/src/main/java/com/android/tools/r8/retrace/Partition.java
+++ b/src/main/java/com/android/tools/r8/retrace/Partition.java
@@ -29,7 +29,7 @@
private static final String USAGE_MESSAGE =
StringUtils.lines(
- "Usage: partition [options] <proguard-map>"
+ "Usage: partition [options] <proguard-map> "
+ "where <proguard-map> is a generated mapping file and options are:");
public static List<ParseFlagInfo> getFlags() {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index 03104f6..fda4b97 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -318,8 +318,7 @@
(type, info) -> {
DexType newType = lens.lookupType(type);
if (newType == options.dexItemFactory().intType) {
- // If the enum has been unboxed, then the keep info is no longer valid. This
- // typically happens for conditional keep rules such as -keepclassmembers.
+ assert !info.isPinned(options);
return;
}
assert newType == type
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 301d7b4..4b80427 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -47,7 +47,6 @@
public final SyntheticKind RETARGET_CLASS = generator.forFixedClass("RetargetClass");
public final SyntheticKind RETARGET_INTERFACE = generator.forFixedClass("RetargetInterface");
public final SyntheticKind WRAPPER = generator.forFixedClass("$Wrapper");
- public final SyntheticKind VIVIFIED = generator.forFixedClass("");
public final SyntheticKind VIVIFIED_WRAPPER = generator.forFixedClass("$VivifiedWrapper");
public final SyntheticKind INIT_TYPE_ARGUMENT = generator.forFixedClass("-IA");
public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_1 =
@@ -169,6 +168,7 @@
}
SyntheticKind forFixedClass(String descriptor) {
+ assert !descriptor.isEmpty();
return register(new SyntheticFixedClassKind(getNextId(), descriptor, false));
}
diff --git a/src/main/java/com/android/tools/r8/utils/Timing.java b/src/main/java/com/android/tools/r8/utils/Timing.java
index 7fef060..1e61b88 100644
--- a/src/main/java/com/android/tools/r8/utils/Timing.java
+++ b/src/main/java/com/android/tools/r8/utils/Timing.java
@@ -13,7 +13,6 @@
// Finally a report is printed by:
// t.report();
-import com.google.common.base.Strings;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
@@ -251,7 +250,7 @@
void printPrefix(int depth) {
if (depth > 0) {
- System.out.print(Strings.repeat(" ", depth));
+ System.out.print(" ".repeat(depth));
System.out.print("- ");
}
}
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index bb2fef7..ef5d163 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -22,7 +22,7 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.OffOrAuto;
import com.android.tools.r8.utils.StringUtils;
-import com.beust.jcommander.internal.Lists;
+import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import java.io.File;
import java.io.IOException;
diff --git a/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java b/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java
index ecfb059..57d23d8 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java
@@ -159,6 +159,7 @@
.addLibraryFiles(dump.getLibraryArchive())
.addKeepRuleFiles(dump.getProguardConfigFile())
.setMinApi(dumpProperties.getMinApi())
+ .allowUnnecessaryDontWarnWildcards()
.allowUnusedDontWarnPatterns()
.allowUnusedProguardConfigurationRules()
// TODO(b/222228826): Disallow unrecognized diagnostics and open interfaces.
@@ -215,6 +216,7 @@
programOutputs.add(
TestBase.testForD8(environment.getTemp(), Backend.DEX)
.addProgramFiles(programFile)
+ .addClasspathFiles(dump.getProgramArchive())
.addLibraryFiles(dump.getLibraryArchive())
.setMinApi(dumpProperties.getMinApi())
.setIntermediate(true)
diff --git a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java
index f87ec27..2537fea 100644
--- a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java
+++ b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java
@@ -22,8 +22,8 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Reporter;
-import com.beust.jcommander.internal.Sets;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java
index c16ec8b..bbfcb4a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java
@@ -183,12 +183,13 @@
this.compilationSpecification = compilationSpecification;
}
+ @SuppressWarnings("RedundantCast")
private String getExpectedResult() {
if (parameters.isCfRuntime()
|| libraryDesugaringSpecification.usesPlatformFileSystem(parameters)) {
- return String.format(EXPECTED_RESULT, EXPECTED_RESULT_NO_DESUGARING);
+ return String.format(EXPECTED_RESULT, (Object[]) EXPECTED_RESULT_NO_DESUGARING);
}
- return String.format(EXPECTED_RESULT, EXPECTED_RESULT_DESUGARING);
+ return String.format(EXPECTED_RESULT, (Object[]) EXPECTED_RESULT_DESUGARING);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/CompanionClassNoSignatureTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/CompanionClassNoSignatureTest.java
new file mode 100644
index 0000000..47b8383
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/CompanionClassNoSignatureTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugaring.interfacemethods;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature;
+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 CompanionClassNoSignatureTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("I.foo");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+ }
+
+ public CompanionClassNoSignatureTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addProgramClasses(I.class, A.class, TestClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(
+ inspector -> {
+ if (parameters
+ .getApiLevel()
+ .isLessThan(apiLevelWithDefaultInterfaceMethodsSupport())) {
+ ClassSignature signature =
+ inspector.companionClassFor(I.class).getDexProgramClass().getClassSignature();
+ assertTrue(
+ "Expected no signature, got: " + signature.toString(),
+ signature.hasNoSignature());
+ }
+ });
+ }
+
+ interface I {
+ default void foo() {
+ System.out.println("I.foo");
+ }
+ }
+
+ static class A implements I {
+ // no override of default.
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ new A().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/CompanionClassWithSignatureTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/CompanionClassWithSignatureTest.java
new file mode 100644
index 0000000..060af3f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/CompanionClassWithSignatureTest.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugaring.interfacemethods;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+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 com.android.tools.r8.graph.GenericSignature.ClassSignature;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class CompanionClassWithSignatureTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+ }
+
+ public CompanionClassWithSignatureTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ public boolean isDesugaring() {
+ return parameters.getApiLevel().isLessThan(apiLevelWithDefaultInterfaceMethodsSupport());
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeFalse(
+ "Art 7 crashes when resolving the default method on I.",
+ parameters.isDexRuntimeVersion(Version.V7_0_0) && !isDesugaring());
+ boolean resolvedBug280356274 = true;
+ String expected = StringUtils.lines(resolvedBug280356274 && isDesugaring() ? "[]" : "[T]");
+ testForD8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(expected)
+ .inspect(
+ inspector -> {
+ // Interface I must retain its signature.
+ assertTrue(
+ inspector.clazz(I.class).getDexProgramClass().getClassSignature().hasSignature());
+ // If desugaring the companion class should not have a signature.
+ if (isDesugaring()) {
+ ClassSignature signature =
+ inspector.companionClassFor(I.class).getDexProgramClass().getClassSignature();
+ assertTrue(
+ "Expected no signature, got: " + signature.toString(),
+ signature.hasNoSignature());
+ }
+ });
+ }
+
+ interface J {}
+
+ interface I<T extends I> extends J {
+ T self();
+
+ default T foo() {
+ Object o = new Object() {};
+ // The class constant here is either the interface I or its companion class.
+ // The desugared companion class is *not* I, thus its type parameters are not the same as
+ // those of I.
+ Class<?> interfaceOrCompanion = o.getClass().getEnclosingMethod().getDeclaringClass();
+ System.out.println(Arrays.toString(interfaceOrCompanion.getTypeParameters()));
+ return self();
+ }
+ }
+
+ static class A implements I<A> {
+
+ @Override
+ public A self() {
+ return this;
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ new A().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/examples/loop/UdpServer.java b/src/test/java/com/android/tools/r8/examples/loop/UdpServer.java
index c76a3ba..9bada3a 100644
--- a/src/test/java/com/android/tools/r8/examples/loop/UdpServer.java
+++ b/src/test/java/com/android/tools/r8/examples/loop/UdpServer.java
@@ -15,18 +15,19 @@
private static final String PREFIX = "RANDOM_DATA_PREFIX_";
public static void main(String[] args) throws Exception {
ExecutorService service = Executors.newWorkStealingPool(2);
- Callable c = new Callable() {
- @Override
- public Object call() throws Exception {
- int counter = 0;
- byte[] receiveData = new byte[1024];
- while (true) {
- // Mimic receiving data via socket. (A use of actual socket is IO blocking.)
- receiveData = (PREFIX + counter++).getBytes();
- }
- }
- };
- Future<?> f = service.submit(c);
+ Callable<Object> c =
+ new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ int counter = 0;
+ byte[] receiveData = new byte[1024];
+ while (true) {
+ // Mimic receiving data via socket. (A use of actual socket is IO blocking.)
+ receiveData = (PREFIX + counter++).getBytes();
+ }
+ }
+ };
+ Future<Object> f = service.submit(c);
try {
f.get(1, TimeUnit.NANOSECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
diff --git a/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java b/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java
index eef3dcf..e220e0a 100644
--- a/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java
+++ b/src/test/java/com/android/tools/r8/internal/opensourceapps/TiviTest.java
@@ -6,8 +6,9 @@
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.R8TestBuilder;
-import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -53,20 +54,6 @@
}
@Test
- public void testR8Recompilation() throws Exception {
- R8TestCompileResult compileResult =
- testForR8(Backend.CF)
- .addProgramFiles(outDirectory.resolve("program.jar"))
- .apply(this::configure)
- .apply(this::configureCf)
- .compile();
- testForR8(Backend.DEX)
- .addProgramFiles(compileResult.writeToZip())
- .apply(this::configure)
- .compile();
- }
-
- @Test
public void testR8Compat() throws Exception {
testForR8Compat(Backend.DEX)
.addProgramFiles(outDirectory.resolve("program.jar"))
@@ -74,20 +61,6 @@
.compile();
}
- @Test
- public void testR8CompatRecompilation() throws Exception {
- R8TestCompileResult compileResult =
- testForR8Compat(Backend.CF)
- .addProgramFiles(outDirectory.resolve("program.jar"))
- .apply(this::configure)
- .apply(this::configureCf)
- .compile();
- testForR8Compat(Backend.DEX)
- .addProgramFiles(compileResult.writeToZip())
- .apply(this::configure)
- .compile();
- }
-
private void configure(R8TestBuilder<?> testBuilder) {
testBuilder
.addClasspathFiles(outDirectory.resolve("classpath.jar"))
@@ -99,10 +72,11 @@
.allowDiagnosticMessages()
.allowUnnecessaryDontWarnWildcards()
.allowUnusedDontWarnPatterns()
- .allowUnusedProguardConfigurationRules();
- }
-
- private void configureCf(R8TestBuilder<?> testBuilder) {
- testBuilder.addOptionsModification(options -> options.horizontalClassMergerOptions().disable());
+ .allowUnusedProguardConfigurationRules()
+ .enableCoreLibraryDesugaring(
+ LibraryDesugaringTestConfiguration.builder()
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(outDirectory.resolve("desugared-library.json")))
+ .build());
}
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
index 6a03cd1..38870bd 100644
--- a/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
@@ -24,7 +24,7 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.beust.jcommander.internal.Lists;
+import com.google.common.collect.Lists;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index 4321812..ade911f 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -13,6 +13,13 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
+import com.android.tools.smali.dexlib2.Opcodes;
+import com.android.tools.smali.dexlib2.writer.builder.DexBuilder;
+import com.android.tools.smali.dexlib2.writer.io.MemoryDataStore;
+import com.android.tools.smali.smali.LexerErrorInterface;
+import com.android.tools.smali.smali.smaliFlexLexer;
+import com.android.tools.smali.smali.smaliParser;
+import com.android.tools.smali.smali.smaliTreeWalker;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.Reader;
@@ -27,13 +34,6 @@
import org.antlr.runtime.TokenSource;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
-import org.jf.dexlib2.Opcodes;
-import org.jf.dexlib2.writer.builder.DexBuilder;
-import org.jf.dexlib2.writer.io.MemoryDataStore;
-import org.jf.smali.LexerErrorInterface;
-import org.jf.smali.smaliFlexLexer;
-import org.jf.smali.smaliParser;
-import org.jf.smali.smaliTreeWalker;
// Adapted from org.jf.smali.SmaliTestUtils.
public class Smali {
@@ -65,7 +65,7 @@
for (String smaliText : smaliTexts) {
Reader reader = new StringReader(smaliText);
- LexerErrorInterface lexer = new smaliFlexLexer(reader);
+ LexerErrorInterface lexer = new smaliFlexLexer(reader, apiLevel);
CommonTokenStream tokens = new CommonTokenStream((TokenSource) lexer);
smaliParser parser = new smaliParser(tokens);
diff --git a/third_party/opensource-apps/tivi.tar.gz.sha1 b/third_party/opensource-apps/tivi.tar.gz.sha1
index dc3e882..1c7e3a4 100644
--- a/third_party/opensource-apps/tivi.tar.gz.sha1
+++ b/third_party/opensource-apps/tivi.tar.gz.sha1
@@ -1 +1 @@
-b5b44fb38064e69308e980fd33651ce03a0b1977
\ No newline at end of file
+97a01f49797a74321ad0181ae078f77d3b226d10
\ No newline at end of file