Merge "Mark field type as live."
diff --git a/build.gradle b/build.gradle
index 8ee6b41..cd831cc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -113,7 +113,6 @@
java {
srcDirs = ['src/test/apiUsageSample']
}
- output.resourcesDir = 'build/classes/apiUsageSample'
}
debugTestResources {
java {
diff --git a/src/main/java/com/android/tools/r8/ApiLevelException.java b/src/main/java/com/android/tools/r8/ApiLevelException.java
index 14a530c..6d110a4 100644
--- a/src/main/java/com/android/tools/r8/ApiLevelException.java
+++ b/src/main/java/com/android/tools/r8/ApiLevelException.java
@@ -3,12 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.utils.AndroidApiLevel;
/**
* Exception to signal features that are not supported until a given API level.
*/
-public class ApiLevelException extends CompilationException {
+public class ApiLevelException extends CompilationError {
public ApiLevelException(
AndroidApiLevel minApiLevel, String unsupportedFeatures, String sourceString) {
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index e393f32..799d834 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -37,7 +37,7 @@
programConsumer = null;
mode = null;
minApiLevel = 0;
- reporter = new Reporter(new DefaultDiagnosticsHandler());
+ reporter = new Reporter(new DefaultDiagnosticsHandler(), this);
enableDesugaring = true;
optimizeMultidexForLinearAlloc = false;
}
diff --git a/src/main/java/com/android/tools/r8/ClassFileConsumer.java b/src/main/java/com/android/tools/r8/ClassFileConsumer.java
index 6d7ad87..6c9a286 100644
--- a/src/main/java/com/android/tools/r8/ClassFileConsumer.java
+++ b/src/main/java/com/android/tools/r8/ClassFileConsumer.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.utils.ArchiveBuilder;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.DirectoryBuilder;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.OutputBuilder;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.io.ByteStreams;
@@ -132,11 +131,7 @@
@Override
public void finished(DiagnosticsHandler handler) {
super.finished(handler);
- try {
- outputBuilder.close();
- } catch (IOException e) {
- handler.error(new ExceptionDiagnostic(e, outputBuilder.getOrigin()));
- }
+ outputBuilder.close(handler);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/CompatDxHelper.java b/src/main/java/com/android/tools/r8/CompatDxHelper.java
index 627f417..f540ed0 100644
--- a/src/main/java/com/android/tools/r8/CompatDxHelper.java
+++ b/src/main/java/com/android/tools/r8/CompatDxHelper.java
@@ -9,8 +9,7 @@
import java.io.IOException;
public class CompatDxHelper {
- public static void run(D8Command command, Boolean minimalMainDex)
- throws IOException, CompilationException {
+ public static void run(D8Command command, Boolean minimalMainDex) throws IOException {
AndroidApp app = command.getInputApp();
InternalOptions options = command.getInternalOptions();
// DX does not desugar.
diff --git a/src/main/java/com/android/tools/r8/CompilationException.java b/src/main/java/com/android/tools/r8/CompilationException.java
deleted file mode 100644
index 8e1e56c..0000000
--- a/src/main/java/com/android/tools/r8/CompilationException.java
+++ /dev/null
@@ -1,52 +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;
-
-/**
- * Exception to signal an compilation error.
- *
- * This is always an expected error and considered a user input issue.
- * A user-understandable message must be provided.
- */
-public class CompilationException extends Exception {
- private static final long serialVersionUID = 1L;
-
- /**
- * Construct the exception with a {@link String} message.
- * @param message the message
- */
- public CompilationException(String message) {
- super(message);
- }
-
- /**
- * Construct the exception with a {@link String} message and a {@link Throwable} cause.
- * @param message the message
- * @param cause the cause
- */
- public CompilationException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Construct the exception with a {@link Throwable} cause.
- * @param cause the cause
- */
- public CompilationException(Throwable cause) {
- super(cause.getMessage(), cause);
- }
-
- protected CompilationException() {
- super();
- }
-
- public String getMessageForD8() {
- return super.getMessage();
- }
-
- public String getMessageForR8() {
- return super.getMessage();
- }
-}
-
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 2d52c64..06cf0bb 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -121,8 +121,7 @@
ExceptionUtils.withMainProgramHandler(() -> run(args));
}
- static void runForTesting(AndroidApp inputApp, InternalOptions options)
- throws IOException, CompilationException {
+ static void runForTesting(AndroidApp inputApp, InternalOptions options) throws IOException {
ExecutorService executor = ThreadUtils.getExecutorService(options);
try {
run(inputApp, options, executor);
@@ -149,7 +148,7 @@
}
private static void run(AndroidApp inputApp, InternalOptions options, ExecutorService executor)
- throws IOException, CompilationException {
+ throws IOException {
Timing timing = new Timing("D8");
try {
// Disable global optimizations.
@@ -196,7 +195,7 @@
InternalOptions options,
Timing timing,
ExecutorService executor)
- throws IOException, ExecutionException, ApiLevelException {
+ throws IOException, ExecutionException {
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
IRConverter converter = new IRConverter(appInfo, options, timing, printer);
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 4c65134..6f956db 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.FlagFile;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -215,9 +216,10 @@
Path outputPath = null;
OutputMode outputMode = null;
boolean hasDefinedApiLevel = false;
+ String[] expandedArgs = FlagFile.expandFlagFiles(args, builder.getReporter());
try {
- for (int i = 0; i < args.length; i++) {
- String arg = args[i].trim();
+ for (int i = 0; i < expandedArgs.length; i++) {
+ String arg = expandedArgs[i].trim();
if (arg.length() == 0) {
continue;
} else if (arg.equals("--help")) {
@@ -243,7 +245,7 @@
} else if (arg.equals("--file-per-class")) {
outputMode = OutputMode.DexFilePerClassFile;
} else if (arg.equals("--output")) {
- String output = args[++i];
+ String output = expandedArgs[++i];
if (outputPath != null) {
builder.getReporter().error(new StringDiagnostic(
"Cannot output both to '" + outputPath.toString() + "' and '" + output + "'",
@@ -252,15 +254,15 @@
}
outputPath = Paths.get(output);
} else if (arg.equals("--lib")) {
- builder.addLibraryFiles(Paths.get(args[++i]));
+ builder.addLibraryFiles(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--classpath")) {
- builder.addClasspathFiles(Paths.get(args[++i]));
+ builder.addClasspathFiles(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--main-dex-list")) {
- builder.addMainDexListFiles(Paths.get(args[++i]));
+ builder.addMainDexListFiles(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--optimize-multidex-for-linearalloc")) {
builder.setOptimizeMultidexForLinearAlloc(true);
} else if (arg.equals("--min-api")) {
- hasDefinedApiLevel = parseMinApi(builder, args[++i], hasDefinedApiLevel, origin);
+ hasDefinedApiLevel = parseMinApi(builder, expandedArgs[++i], hasDefinedApiLevel, origin);
} else if (arg.equals("--intermediate")) {
builder.setIntermediate(true);
} else if (arg.equals("--no-desugaring")) {
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
index 9c76484..5987b99 100644
--- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
+++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -67,7 +67,7 @@
InternalOptions options,
Boolean minimalMainDex,
Map<String, Integer> inputOrdering)
- throws IOException, CompilationException {
+ throws IOException {
options.enableDesugaring = false;
options.enableMainDexListCheck = false;
options.minimalMainDex = minimalMainDex;
@@ -106,7 +106,7 @@
}
public static void runD8ForTesting(D8Command command, boolean dontCreateMarkerInD8)
- throws IOException, CompilationException {
+ throws IOException {
InternalOptions options = command.getInternalOptions();
options.testing.dontCreateMarkerInD8 = dontCreateMarkerInD8;
D8.runForTesting(command.getInputApp(), options);
diff --git a/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java b/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java
index ca86c70..f1c0fac 100644
--- a/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java
+++ b/src/main/java/com/android/tools/r8/DexFilePerClassFileConsumer.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.utils.ArchiveBuilder;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.DirectoryBuilder;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.OutputBuilder;
import com.android.tools.r8.utils.ZipUtils;
@@ -153,11 +152,7 @@
@Override
public void finished(DiagnosticsHandler handler) {
super.finished(handler);
- try {
- outputBuilder.close();
- } catch (IOException e) {
- handler.error(new ExceptionDiagnostic(e, outputBuilder.getOrigin()));
- }
+ outputBuilder.close(handler);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
index f26ab73..3bbab64 100644
--- a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
+++ b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
@@ -156,11 +156,7 @@
@Override
public void finished(DiagnosticsHandler handler) {
super.finished(handler);
- try {
- outputBuilder.close();
- } catch (IOException e) {
- handler.error(new ExceptionDiagnostic(e, outputBuilder.getOrigin()));
- }
+ outputBuilder.close(handler);
}
public static void writeResources(Path archive, List<ProgramResource> resources)
@@ -242,11 +238,7 @@
@Override
public void finished(DiagnosticsHandler handler) {
super.finished(handler);
- try {
- outputBuilder.close();
- } catch (IOException e) {
- handler.error(new ExceptionDiagnostic(e, outputBuilder.getOrigin()));
- }
+ outputBuilder.close(handler);
}
private synchronized void prepareDirectory() throws IOException {
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index 1fcd70a..2d52ec9 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -40,8 +40,7 @@
try {
ExceptionUtils.withCompilationHandler(
command.getReporter(),
- () -> run(command, featureClassMapping, output, proguardMap, executor),
- CompilationException::getMessage);
+ () -> run(command, featureClassMapping, output, proguardMap, executor));
} finally {
executor.shutdown();
}
@@ -53,7 +52,7 @@
String output,
String proguardMap,
ExecutorService executor)
- throws IOException, CompilationException {
+ throws IOException {
InternalOptions options = command.getInternalOptions();
options.enableDesugaring = false;
options.enableMainDexListCheck = false;
@@ -135,7 +134,7 @@
}
public static void runD8ForTesting(D8Command command, boolean dontCreateMarkerInD8)
- throws IOException, CompilationException {
+ throws IOException {
InternalOptions options = command.getInternalOptions();
options.testing.dontCreateMarkerInD8 = dontCreateMarkerInD8;
D8.runForTesting(command.getInputApp(), options);
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index ced0b4c..734dc4a 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -94,7 +94,7 @@
}
public static void main(String[] args)
- throws IOException, CompilationException, ExecutionException, ResourceException {
+ throws IOException, ExecutionException, ResourceException {
ExtractMarkerCommand.Builder builder = ExtractMarkerCommand.parse(args);
ExtractMarkerCommand command = builder.build();
if (command.isPrintHelp()) {
diff --git a/src/main/java/com/android/tools/r8/ExtractMarkerCommand.java b/src/main/java/com/android/tools/r8/ExtractMarkerCommand.java
index 9555d3b..598d8e0 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarkerCommand.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarkerCommand.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.errors.CompilationError;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
@@ -54,7 +55,7 @@
return this;
}
- public ExtractMarkerCommand build() throws CompilationException, IOException {
+ public ExtractMarkerCommand build() throws IOException {
// If printing versions ignore everything else.
if (isPrintHelp()) {
return new ExtractMarkerCommand(isPrintHelp());
@@ -76,15 +77,13 @@
return new Builder();
}
- public static Builder parse(String[] args)
- throws CompilationException, IOException {
+ public static Builder parse(String[] args) throws IOException {
Builder builder = builder();
parse(args, builder);
return builder;
}
- private static void parse(String[] args, Builder builder)
- throws CompilationException, IOException {
+ private static void parse(String[] args, Builder builder) throws IOException {
for (int i = 0; i < args.length; i++) {
String arg = args[i].trim();
if (arg.length() == 0) {
@@ -101,7 +100,7 @@
builder.setPrintHelp(true);
} else {
if (arg.startsWith("--")) {
- throw new CompilationException("Unknown option: " + arg);
+ throw new CompilationError("Unknown option: " + arg);
}
builder.addProgramFile(Paths.get(arg));
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 53e2f87..5d29d90 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.ClassAndMemberPublicizer;
import com.android.tools.r8.graph.DexApplication;
@@ -89,7 +88,7 @@
* <p>R8 supports some configuration using configuration files mostly compatible with the format of
* the <a href="https://www.guardsquare.com/en/proguard">ProGuard</a> optimizer.
*
- * <p>The compiler is invoked by calling {@link #run(R8Command) R8.run} with an appropriate {@link
+ * <p>The compiler is invoked by calling {@link #run(R8Command) R8.run} with an appropriate {link
* R8Command}. For example:
*
* <pre>
@@ -179,7 +178,7 @@
String proguardSeedsData,
InternalOptions options,
ProguardMapSupplier proguardMapSupplier)
- throws ExecutionException, DexOverflowException {
+ throws ExecutionException {
try {
Marker marker = getMarker(options);
if (options.isGeneratingClassFiles()) {
@@ -214,8 +213,7 @@
return result;
}
- static void runForTesting(AndroidApp app, InternalOptions options)
- throws IOException, CompilationException {
+ static void runForTesting(AndroidApp app, InternalOptions options) throws IOException {
ExecutorService executor = ThreadUtils.getExecutorService(options);
try {
run(app, options, executor);
@@ -224,16 +222,12 @@
}
}
- private static void run(
- AndroidApp app,
- InternalOptions options,
- ExecutorService executor)
- throws IOException, CompilationException {
+ private static void run(AndroidApp app, InternalOptions options, ExecutorService executor)
+ throws IOException {
new R8(options).run(app, executor);
}
- private void run(AndroidApp inputApp, ExecutorService executorService)
- throws IOException, CompilationException {
+ private void run(AndroidApp inputApp, ExecutorService executorService) throws IOException {
assert options.programConsumer != null;
if (options.quiet) {
System.setOut(new PrintStream(ByteStreams.nullOutputStream()));
@@ -503,31 +497,15 @@
}
}
- static void unwrapExecutionException(ExecutionException executionException)
- throws CompilationException {
+ static void unwrapExecutionException(ExecutionException executionException) {
Throwable cause = executionException.getCause();
if (cause instanceof CompilationError) {
// add original exception as suppressed exception to provide the original stack trace
cause.addSuppressed(executionException);
throw (CompilationError) cause;
- } else if (cause instanceof CompilationException) {
- cause.addSuppressed(executionException);
- throw (CompilationException) cause;
} else if (cause instanceof RuntimeException) {
- // ForkJoinPool wraps checked exceptions in RuntimeExceptions
- if (cause.getCause() != null
- && cause.getCause() instanceof CompilationException) {
- cause.addSuppressed(executionException);
- throw (CompilationException) cause.getCause();
- // ForkJoinPool sometimes uses 2 levels of RuntimeExceptions, to provide accurate stack traces
- } else if (cause.getCause() != null && cause.getCause().getCause() != null
- && cause.getCause().getCause() instanceof CompilationException) {
- cause.addSuppressed(executionException);
- throw (CompilationException) cause.getCause().getCause();
- } else {
- cause.addSuppressed(executionException);
- throw (RuntimeException) cause;
- }
+ cause.addSuppressed(executionException);
+ throw (RuntimeException) cause;
} else {
throw new RuntimeException(executionException.getMessage(), cause);
}
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index dafa35a..573f6df 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -18,12 +18,12 @@
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.FlagFile;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.common.collect.ImmutableList;
-import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -66,6 +66,8 @@
// Internal compatibility mode for use from CompatProguard tool.
Path proguardCompatibilityRulesOutput = null;
+ private boolean allowPartiallyImplementedProguardOptions = false;
+
private StringConsumer mainDexListConsumer = null;
// TODO(zerny): Consider refactoring CompatProguardCommandBuilder to avoid subclassing.
@@ -286,7 +288,8 @@
mainDexKeepRules = parser.getConfig().getRules();
}
- ProguardConfigurationParser parser = new ProguardConfigurationParser(factory, reporter);
+ ProguardConfigurationParser parser = new ProguardConfigurationParser(
+ factory, reporter, !allowPartiallyImplementedProguardOptions);
if (!proguardConfigs.isEmpty()) {
parser.parse(proguardConfigs);
}
@@ -384,6 +387,11 @@
c.accept(builder);
};
}
+
+ // Internal for-testing method to add post-processors of the proguard configuration.
+ void allowPartiallyImplementedProguardOptions() {
+ allowPartiallyImplementedProguardOptions = true;
+ }
}
// Wrapper class to ensure that R8 does not allow DEX as program inputs.
@@ -514,8 +522,9 @@
Origin argsOrigin,
Builder builder,
ParseState state) {
- for (int i = 0; i < args.length; i++) {
- String arg = args[i].trim();
+ String[] expandedArgs = FlagFile.expandFlagFiles(args, builder.getReporter());
+ for (int i = 0; i < expandedArgs.length; i++) {
+ String arg = expandedArgs[i].trim();
if (arg.length() == 0) {
continue;
} else if (arg.equals("--help")) {
@@ -547,7 +556,7 @@
}
state.outputMode = OutputMode.ClassFile;
} else if (arg.equals("--output")) {
- String outputPath = args[++i];
+ String outputPath = expandedArgs[++i];
if (state.outputPath != null) {
builder.getReporter().error(new StringDiagnostic(
"Cannot output both to '"
@@ -559,10 +568,10 @@
}
state.outputPath = Paths.get(outputPath);
} else if (arg.equals("--lib")) {
- builder.addLibraryFiles(Paths.get(args[++i]));
+ builder.addLibraryFiles(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--min-api")) {
state.hasDefinedApiLevel =
- parseMinApi(builder, args[++i], state.hasDefinedApiLevel, argsOrigin);
+ parseMinApi(builder, expandedArgs[++i], state.hasDefinedApiLevel, argsOrigin);
} else if (arg.equals("--no-tree-shaking")) {
builder.setDisableTreeShaking(true);
} else if (arg.equals("--no-minification")) {
@@ -570,40 +579,17 @@
} else if (arg.equals("--no-desugaring")) {
builder.setDisableDesugaring(true);
} else if (arg.equals("--main-dex-rules")) {
- builder.addMainDexRulesFiles(Paths.get(args[++i]));
+ builder.addMainDexRulesFiles(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--main-dex-list")) {
- builder.addMainDexListFiles(Paths.get(args[++i]));
+ builder.addMainDexListFiles(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--main-dex-list-output")) {
- builder.setMainDexListOutputPath(Paths.get(args[++i]));
+ builder.setMainDexListOutputPath(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--optimize-multidex-for-linearalloc")) {
builder.setOptimizeMultidexForLinearAlloc(true);
} else if (arg.equals("--pg-conf")) {
- builder.addProguardConfigurationFiles(Paths.get(args[++i]));
+ builder.addProguardConfigurationFiles(Paths.get(expandedArgs[++i]));
} else if (arg.equals("--pg-map-output")) {
- builder.setProguardMapOutputPath(Paths.get(args[++i]));
- } else if (arg.startsWith("@")) {
- // TODO(zerny): Replace this with pipe reading.
- Path argsFile = Paths.get(arg.substring(1));
- Origin argsFileOrigin = new PathOrigin(argsFile);
- try {
- List<String> linesInFile = FileUtils.readAllLines(argsFile);
- List<String> argsInFile = new ArrayList<>();
- for (String line : linesInFile) {
- for (String word : line.split("\\s")) {
- String trimmed = word.trim();
- if (!trimmed.isEmpty()) {
- argsInFile.add(trimmed);
- }
- }
- }
- // TODO(zerny): We need to define what CWD should be for files referenced in an args file.
- state = parse(argsInFile.toArray(new String[argsInFile.size()]),
- argsFileOrigin, builder, state);
- } catch (IOException e) {
- builder.getReporter().error(new StringDiagnostic(
- "Failed to read arguments from file " + argsFile + ": " + e.getMessage(),
- argsFileOrigin));
- }
+ builder.setProguardMapOutputPath(Paths.get(expandedArgs[++i]));
} else {
if (arg.startsWith("--")) {
builder.getReporter().error(new StringDiagnostic("Unknown option: " + arg, argsOrigin));
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 98ed5e9..24b2cc9 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.2.17-dev";
+ public static final String LABEL = "1.2.19-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/benchmarks/FrameworkIncrementalDexingBenchmark.java b/src/main/java/com/android/tools/r8/benchmarks/FrameworkIncrementalDexingBenchmark.java
index 250ca3b..1336f95 100644
--- a/src/main/java/com/android/tools/r8/benchmarks/FrameworkIncrementalDexingBenchmark.java
+++ b/src/main/java/com/android/tools/r8/benchmarks/FrameworkIncrementalDexingBenchmark.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.benchmarks.BenchmarkUtils.printRuntimeNanoseconds;
import com.android.tools.r8.ClassFileResourceProvider;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
@@ -112,7 +111,7 @@
boolean desugar,
Map<String, ProgramResource> outputs,
ExecutorService executor)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
ProgramConsumer consumer =
new DexFilePerClassFileConsumer.ForwardingConsumer(null) {
@@ -155,7 +154,7 @@
boolean desugar,
Map<String, ProgramResource> outputs,
ExecutorService executor)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
ProgramConsumer consumer =
new ForwardingConsumer(null) {
@Override
@@ -199,7 +198,7 @@
private static void merge(
boolean desugar, Map<String, ProgramResource> outputs, ExecutorService executor)
- throws IOException, CompilationException, CompilationFailedException, ResourceException {
+ throws IOException, CompilationFailedException, ResourceException {
Builder builder =
D8Command.builder()
.setMinApiLevel(API)
@@ -221,7 +220,7 @@
}
public static void main(String[] args)
- throws IOException, CompilationException, CompilationFailedException, ResourceException {
+ throws IOException, CompilationFailedException, ResourceException {
boolean desugar = Arrays.asList(args).contains("--desugar");
Path input = desugar ? JAR_NOT_DESUGARED : JAR_DESUGARED;
InMemoryClassPathProvider provider = new InMemoryClassPathProvider(input);
diff --git a/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java b/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java
index 0aaefd9..3f241a0 100644
--- a/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java
+++ b/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
@@ -20,7 +19,7 @@
private static final int ITERATIONS = 1000;
public static void compile(ExecutorService executor)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
D8.run(
D8Command.builder()
.addProgramFiles(Paths.get("build/test/examples/arithmetic.jar"))
@@ -43,8 +42,7 @@
executor);
}
- public static void main(String[] args)
- throws IOException, CompilationException, CompilationFailedException {
+ public static void main(String[] args) throws IOException, CompilationFailedException {
int threads = Integer.min(Runtime.getRuntime().availableProcessors(), 16) / 2;
ExecutorService executor = ThreadUtils.getExecutorService(threads);
try {
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index dcc89c6..7ef43a3 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.utils.AndroidApp;
@@ -175,7 +174,7 @@
}
private static void writeApp(DexApplication app, Path output, ExecutorService executor)
- throws IOException, ExecutionException, DexOverflowException {
+ throws IOException, ExecutionException {
InternalOptions options = new InternalOptions();
AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
ApplicationWriter writer = new ApplicationWriter(app, options, null, null, null, null, null);
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 0a98cb3..3122404 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexType;
@@ -48,8 +47,7 @@
}
@Override
- public void buildIR(IRBuilder builder, CfState state, CfSourceCode code)
- throws ApiLevelException {
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
builder.addConstMethodHandle(
state.push(builder.getFactory().methodHandleType).register, handle);
}
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 e933c11..ebbaf21 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
@@ -49,8 +48,7 @@
}
@Override
- public void buildIR(IRBuilder builder, CfState state, CfSourceCode code)
- throws ApiLevelException {
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
builder.addConstMethodType(state.push(builder.getFactory().methodTypeType).register, type);
}
}
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 eaa7b2a..6d2a3d5 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.UseRegistry;
@@ -49,8 +48,7 @@
return false;
}
- public abstract void buildIR(IRBuilder builder, CfState state, CfSourceCode code)
- throws ApiLevelException;
+ public abstract void buildIR(IRBuilder builder, CfState state, CfSourceCode code);
/** Return true if this instruction directly emits IR instructions. */
public boolean emitsIR() {
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 32c7022..5dfef0c 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
@@ -91,8 +90,7 @@
}
@Override
- public void buildIR(IRBuilder builder, CfState state, CfSourceCode code)
- throws ApiLevelException {
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
Invoke.Type type;
DexMethod canonicalMethod;
DexProto callSiteProto = null;
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 2dfc8fa..015b8a3 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.UseRegistry;
@@ -52,8 +51,7 @@
}
@Override
- public void buildIR(IRBuilder builder, CfState state, CfSourceCode code)
- throws ApiLevelException {
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
int[] dimensions = state.popReverse(this.dimensions);
builder.addMultiNewArray(type, state.push(type).register, dimensions);
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
index a346020..bad4e47 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -71,7 +70,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addConstMethodHandle(AA, (DexMethodHandle) BBBB);
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
index 6a1bef5..84c090a 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -71,7 +70,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addConstMethodType(AA, (DexProto) BBBB);
}
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArray.java b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
index 8aaf5b9..4f2ebb6 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArray.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.ir.conversion.IRBuilder;
@@ -42,7 +41,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeNewArray(getType(), A, new int[]{C, D, E, F, G});
}
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
index 2d39d50..0ee63b0 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.ir.conversion.IRBuilder;
@@ -42,7 +41,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRangeNewArray(getType(), AA, CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index 09d5671b..c8b5154 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.DexCallSite;
@@ -184,7 +183,7 @@
return NO_TARGETS;
}
- public abstract void buildIR(IRBuilder builder) throws ApiLevelException;
+ public abstract void buildIR(IRBuilder builder);
public DexCallSite getCallSite() {
return null;
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/code/InvokeDirect.java
index 06b919b..08d6826 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeDirect.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -51,7 +50,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRegisters(Type.DIRECT, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
index e2b129d..8f72a2b 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.UseRegistry;
@@ -50,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRange(Type.DIRECT, getMethod(), getProto(), AA, CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/code/InvokeInterface.java
index c0d912a..b98af41 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeInterface.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -51,7 +50,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRegisters(
Type.INTERFACE, getMethod(), getProto(), A, new int[] {C, D, E, F, G});
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
index c63c41b..e4d63b4 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.UseRegistry;
@@ -50,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRange(Type.INTERFACE, getMethod(), getProto(), AA, CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java
index 891dcca..d5ecd11 100644
--- a/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -30,7 +29,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRegisters(
Type.POLYMORPHIC, getMethod(), getProto(), A, new int[] {C, D, E, F, G});
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java b/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java
index 3969a8c..45eb6e8 100644
--- a/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -53,7 +52,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRange(Type.POLYMORPHIC, getMethod(), getProto(), AA, CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/code/InvokeStatic.java
index 6c0a724..73cb887 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeStatic.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.UseRegistry;
@@ -50,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRegisters(Type.STATIC, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
index 912cd4b..6fd3f42 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.UseRegistry;
@@ -50,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRange(Type.STATIC, getMethod(), getProto(), AA, CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/code/InvokeSuper.java
index 10ed497..9575ed9 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeSuper.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -51,7 +50,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRegisters(Type.SUPER, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
index 8933527..63c6318 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.UseRegistry;
@@ -50,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRange(Type.SUPER, getMethod(), getProto(), AA, CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
index 132c564..003debf 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.UseRegistry;
@@ -50,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRegisters(Type.VIRTUAL, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
index 00cb861..64e9b6d 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.UseRegistry;
@@ -50,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) throws ApiLevelException {
+ public void buildIR(IRBuilder builder) {
builder.addInvokeRange(Type.VIRTUAL, getMethod(), getProto(), AA, CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilder.java b/src/main/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilder.java
index b270200..6599591 100644
--- a/src/main/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilder.java
+++ b/src/main/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilder.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.compatdexbuilder;
import com.android.tools.r8.CompatDxHelper;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
@@ -154,7 +153,7 @@
}
private DexConsumer dexEntry(ZipFile zipFile, ZipEntry classEntry, ExecutorService executor)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
DexConsumer consumer = new DexConsumer();
D8Command.Builder builder = D8Command.builder();
CompatDxHelper.ignoreDexInArchive(builder);
diff --git a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
index b9131e5..f512a34 100644
--- a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
+++ b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
@@ -11,7 +11,6 @@
import static com.android.tools.r8.utils.FileUtils.isZipFile;
import com.android.tools.r8.CompatDxHelper;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8Command;
@@ -312,9 +311,6 @@
public static void main(String[] args) throws IOException {
try {
run(args);
- } catch (CompilationException e) {
- System.err.println(e.getMessage());
- System.exit(1);
} catch (DxUsageMessage e) {
System.err.println(USAGE_HEADER);
e.printHelpOn(System.err);
@@ -325,7 +321,7 @@
}
private static void run(String[] args)
- throws DxUsageMessage, IOException, CompilationException, CompilationFailedException {
+ throws DxUsageMessage, IOException, CompilationFailedException {
DxCompatOptions dexArgs = DxCompatOptions.parse(args);
if (dexArgs.help) {
printHelpOn(System.out);
diff --git a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
index 66931e3..615a3e2 100644
--- a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
+++ b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
@@ -5,12 +5,12 @@
package com.android.tools.r8.compatproguard;
import com.android.tools.r8.CompatProguardCommandBuilder;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.Version;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.utils.AbortException;
import com.google.common.collect.ImmutableList;
@@ -58,7 +58,7 @@
this.printHelpAndExit = printHelpAndExit;
}
- public static CompatProguardOptions parse(String[] args) throws CompilationException {
+ public static CompatProguardOptions parse(String[] args) {
String output = null;
int minApi = 1;
boolean forceProguardCompatibility = false;
@@ -97,7 +97,7 @@
} else if (arg.equals("--no-locals")) {
noLocals = true;
} else if (arg.equals("-outjars")) {
- throw new CompilationException(
+ throw new CompilationError(
"Proguard argument -outjar is not supported. Use R8 compatible --output flag");
} else {
if (currentLine.length() > 0) {
@@ -150,8 +150,7 @@
CompatProguardOptions.print();
}
- private static void run(String[] args)
- throws IOException, CompilationException, CompilationFailedException {
+ private static void run(String[] args) throws IOException, CompilationFailedException {
// Run R8 passing all the options from the command line as a Proguard configuration.
CompatProguardOptions options = CompatProguardOptions.parse(args);
if (options.printHelpAndExit || options.output == null) {
@@ -175,9 +174,6 @@
public static void main(String[] args) throws IOException {
try {
run(args);
- } catch (CompilationException e) {
- System.err.println(e.getMessage());
- System.exit(1);
} catch (CompilationFailedException | AbortException e) {
// Detail of the errors were already reported
System.err.println("Compilation failed");
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 382bc66..e1905ff 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dex;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.DataDirectoryResource;
import com.android.tools.r8.DataEntryResource;
import com.android.tools.r8.DataResourceConsumer;
@@ -13,7 +12,6 @@
import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationDirectory;
import com.android.tools.r8.graph.DexAnnotationSet;
@@ -163,7 +161,7 @@
}
private Iterable<VirtualFile> distribute(ExecutorService executorService)
- throws ExecutionException, IOException, DexOverflowException {
+ throws ExecutionException, IOException {
// Distribute classes into dex files.
VirtualFile.Distributor distributor;
if (options.isGeneratingDexFilePerClassFile()) {
@@ -180,8 +178,7 @@
return distributor.run();
}
- public void write(ExecutorService executorService)
- throws IOException, ExecutionException, DexOverflowException {
+ public void write(ExecutorService executorService) throws IOException, ExecutionException {
application.timing.begin("DexApplication.write");
try {
insertAttributeAnnotations();
@@ -200,7 +197,6 @@
// Use a linked hash map as the order matters when addDexProgramData is called below.
Map<VirtualFile, Future<ObjectToOffsetMapping>> offsetMappingFutures = new LinkedHashMap<>();
for (VirtualFile newFile : distribute(executorService)) {
- assert !newFile.isEmpty();
if (!newFile.isEmpty()) {
offsetMappingFutures
.put(newFile, executorService.submit(() -> {
@@ -429,8 +425,7 @@
}
}
- private byte[] writeDexFile(ObjectToOffsetMapping mapping)
- throws ApiLevelException {
+ private byte[] writeDexFile(ObjectToOffsetMapping mapping) {
FileWriter fileWriter = new FileWriter(mapping, application, options, namingLens);
// Collect the non-fixed sections.
fileWriter.collect();
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 4767c64..b73f8a4 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -51,7 +51,6 @@
import com.android.tools.r8.utils.DexVersion;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.LebUtils;
-import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
@@ -135,7 +134,7 @@
return this;
}
- public byte[] generate() throws ApiLevelException {
+ public byte[] generate() {
// Check restrictions on interface methods.
checkInterfaceMethods();
@@ -203,7 +202,7 @@
return Arrays.copyOf(dest.asArray(), layout.getEndOfFile());
}
- private void checkInterfaceMethods() throws ApiLevelException {
+ private void checkInterfaceMethods() {
for (DexProgramClass clazz : mapping.getClasses()) {
if (clazz.isInterface()) {
for (DexEncodedMethod method : clazz.directMethods()) {
@@ -222,7 +221,7 @@
// -- starting with N interfaces may also have public or private
// static methods, as well as public non-abstract (default)
// and private instance methods.
- private void checkInterfaceMethod(DexEncodedMethod method) throws ApiLevelException {
+ private void checkInterfaceMethod(DexEncodedMethod method) {
if (application.dexItemFactory.isClassConstructor(method.method)) {
return; // Class constructor is always OK.
}
@@ -295,16 +294,16 @@
}
}
- private <T extends IndexedDexItem> void writeFixedSectionItems(Collection<T> items, int offset,
- ThrowingConsumer<T, ApiLevelException> writer) throws ApiLevelException {
+ private <T extends IndexedDexItem> void writeFixedSectionItems(
+ Collection<T> items, int offset, Consumer<T> writer) {
assert dest.position() == offset;
for (T item : items) {
writer.accept(item);
}
}
- private void writeFixedSectionItems(DexProgramClass[] items, int offset,
- ThrowingConsumer<DexProgramClass, ApiLevelException> writer) throws ApiLevelException {
+ private void writeFixedSectionItems(
+ DexProgramClass[] items, int offset, Consumer<DexProgramClass> writer) {
assert dest.position() == offset;
for (DexProgramClass item : items) {
writer.accept(item);
@@ -610,7 +609,7 @@
}
}
- private void writeMethodHandle(DexMethodHandle methodHandle) throws ApiLevelException {
+ private void writeMethodHandle(DexMethodHandle methodHandle) {
checkThatInvokeCustomIsAllowed();
MethodHandleType methodHandleDexType;
switch (methodHandle.type) {
@@ -636,7 +635,7 @@
dest.putShort((short) 0); // unused
}
- private void writeCallSite(DexCallSite callSite) throws ApiLevelException {
+ private void writeCallSite(DexCallSite callSite) {
checkThatInvokeCustomIsAllowed();
assert dest.isAligned(4);
dest.putInt(mixedSectionOffsets.getOffsetFor(callSite.getEncodedArray()));
@@ -1296,7 +1295,7 @@
}
}
- private void checkThatInvokeCustomIsAllowed() throws ApiLevelException {
+ private void checkThatInvokeCustomIsAllowed() {
if (!options.canUseInvokeCustom()) {
throw new ApiLevelException(
AndroidApiLevel.O,
diff --git a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
index 3d0b01c..9e75e45 100644
--- a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
+++ b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.dex;
import com.android.tools.r8.dex.VirtualFile.VirtualFileCycler;
-import com.android.tools.r8.errors.DexOverflowException;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexProgramClass;
@@ -306,7 +306,7 @@
directSubClasses = new DirectSubClassesInfo(app, classes);
}
- public void distribute() throws DexOverflowException {
+ public void distribute() {
List<ClassGroup> remainingInheritanceGroups = collectInheritanceGroups();
// Sort to ensure reproducible allocation
remainingInheritanceGroups.sort(null);
@@ -369,8 +369,7 @@
return groupClassNumber;
}
- private Collection<VirtualFile> assignGroup(ClassGroup group,
- List<VirtualFile> dexBlackList) throws DexOverflowException {
+ private Collection<VirtualFile> assignGroup(ClassGroup group, List<VirtualFile> dexBlackList) {
VirtualFileCycler cycler = new VirtualFileCycler(dexes, namingLens, dexIndexOffset);
if (group.members.isEmpty()) {
return Collections.emptyList();
@@ -411,8 +410,8 @@
* They will fail to link during DexOpt but they will be loaded only once.
* @param classes set of classes to assign, the set will be destroyed during assignment.
*/
- private Collection<VirtualFile> assignClassesWithLinkingError(Set<DexProgramClass> classes,
- Collection<VirtualFile> dexBlackList) throws DexOverflowException {
+ private Collection<VirtualFile> assignClassesWithLinkingError(
+ Set<DexProgramClass> classes, Collection<VirtualFile> dexBlackList) {
List<ClassGroup> layers = collectNoDirectInheritanceGroups(classes);
@@ -440,7 +439,7 @@
dexForLayer.abortTransaction();
if (dexForLayer.isEmpty()) {
// The class is too big to fit in one dex
- throw new DexOverflowException("Class '" + dexProgramClass.toSourceString()
+ throw new CompilationError("Class '" + dexProgramClass.toSourceString()
+ "' from " + dexProgramClass.getOrigin().toString()
+ " is too big to fit in a dex.");
}
@@ -614,8 +613,8 @@
* Assign as many classes as possible by layer starting by roots.
* @return the list of classes that were not assigned.
*/
- private Set<DexProgramClass> assignFromRoot(VirtualFile dex,
- Collection<DexProgramClass> classes) throws DexOverflowException {
+ private Set<DexProgramClass> assignFromRoot(
+ VirtualFile dex, Collection<DexProgramClass> classes) {
int totalClasses = classes.size();
int assignedClasses = 0;
@@ -635,7 +634,7 @@
dex.abortTransaction();
if (dex.isEmpty()) {
// The class is too big to fit in one dex
- throw new DexOverflowException("Class '" + clazz.toSourceString() + "' from "
+ throw new CompilationError("Class '" + clazz.toSourceString() + "' from "
+ clazz.getOrigin().toString() + " is too big to fit in a dex.");
}
isLayerFullyAssigned = false;
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 7f55b19..9ac752a 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -3,9 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dex;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.errors.InternalCompilerError;
-import com.android.tools.r8.errors.MainDexOverflowException;
+import com.android.tools.r8.errors.MainDexOverflow;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
@@ -24,6 +23,7 @@
import com.android.tools.r8.utils.DescriptorUtils;
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 com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
@@ -185,15 +185,16 @@
return transaction.getNumberOfFields();
}
- void throwIfFull(boolean hasMainDexList) throws DexOverflowException {
+ void throwIfFull(boolean hasMainDexList, Reporter reporter) {
if (!isFull()) {
return;
}
- throw new MainDexOverflowException(
- hasMainDexList,
- transaction.getNumberOfMethods(),
- transaction.getNumberOfFields(),
- MAX_ENTRIES);
+ throw reporter.fatalError(
+ new MainDexOverflow(
+ hasMainDexList,
+ transaction.getNumberOfMethods(),
+ transaction.getNumberOfFields(),
+ MAX_ENTRIES));
}
private boolean isFilledEnough(FillStrategy fillStrategy) {
@@ -226,8 +227,7 @@
this.writer = writer;
}
- public abstract Collection<VirtualFile> run()
- throws ExecutionException, IOException, DexOverflowException;
+ public abstract Collection<VirtualFile> run() throws ExecutionException, IOException;
}
/**
@@ -296,7 +296,7 @@
originalNames = computeOriginalNameMapping(classes, application.getProguardMap());
}
- protected void fillForMainDexList(Set<DexProgramClass> classes) throws DexOverflowException {
+ protected void fillForMainDexList(Set<DexProgramClass> classes) {
if (!application.mainDexList.isEmpty()) {
VirtualFile mainDexFile = virtualFiles.get(0);
for (DexType type : application.mainDexList) {
@@ -314,7 +314,7 @@
}
mainDexFile.commitTransaction();
}
- mainDexFile.throwIfFull(true);
+ mainDexFile.throwIfFull(true, options.reporter);
}
}
@@ -363,7 +363,7 @@
}
@Override
- public Collection<VirtualFile> run() throws IOException, DexOverflowException {
+ public Collection<VirtualFile> run() throws IOException {
int totalClassNumber = classes.size();
// First fill required classes into the main dex file.
fillForMainDexList(classes);
@@ -408,14 +408,13 @@
}
@Override
- public Collection<VirtualFile> run()
- throws ExecutionException, IOException, DexOverflowException {
+ public Collection<VirtualFile> run() throws ExecutionException, IOException {
// Add all classes to the main dex file.
for (DexProgramClass programClass : classes) {
mainDexFile.addClass(programClass);
}
mainDexFile.commitTransaction();
- mainDexFile.throwIfFull(false);
+ mainDexFile.throwIfFull(false, options.reporter);
return virtualFiles;
}
}
diff --git a/src/main/java/com/android/tools/r8/errors/DexOverflowException.java b/src/main/java/com/android/tools/r8/errors/DexOverflowException.java
deleted file mode 100644
index a392080..0000000
--- a/src/main/java/com/android/tools/r8/errors/DexOverflowException.java
+++ /dev/null
@@ -1,20 +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.errors;
-
-import com.android.tools.r8.CompilationException;
-
-/**
- * Signals when there were too many items to fit in a given dex file.
- */
-public class DexOverflowException extends CompilationException {
-
- protected DexOverflowException() {
- super();
- }
-
- public DexOverflowException(String message) {
- super(message);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/errors/MainDexOverflowException.java b/src/main/java/com/android/tools/r8/errors/MainDexOverflow.java
similarity index 89%
rename from src/main/java/com/android/tools/r8/errors/MainDexOverflowException.java
rename to src/main/java/com/android/tools/r8/errors/MainDexOverflow.java
index e570c81..e33cf59 100644
--- a/src/main/java/com/android/tools/r8/errors/MainDexOverflowException.java
+++ b/src/main/java/com/android/tools/r8/errors/MainDexOverflow.java
@@ -4,16 +4,16 @@
package com.android.tools.r8.errors;
/**
- * Thrown when running mono dex and not all classes can fit in a dex or when running for multidex
- * legacy and there are too many classes to fit in the main dex.
+ * Info about error when running mono dex and not all classes can fit in a dex or when running for
+ * multidex legacy and there are too many classes to fit in the main dex.
*/
-public class MainDexOverflowException extends DexOverflowException {
+public class MainDexOverflow {
private final boolean hasMainDexList;
private final long numOfMethods;
private final long numOfFields;
private final long maxNumOfEntries;
- public MainDexOverflowException(
+ public MainDexOverflow(
boolean hasMainDexList, long numOfMethods, long numOfFields, long maxNumOfEntries) {
super();
this.hasMainDexList = hasMainDexList;
@@ -52,7 +52,6 @@
return messageBuilder.toString();
}
- @Override
public String getMessage() {
// Default message
return getGeneralMessage()
@@ -62,7 +61,6 @@
.toString();
}
- @Override
public String getMessageForD8() {
StringBuilder messageBuilder = getGeneralMessage();
if (!hasMainDexList) {
@@ -74,7 +72,6 @@
return messageBuilder.toString();
}
- @Override
public String getMessageForR8() {
StringBuilder messageBuilder = getGeneralMessage();
if (!hasMainDexList) {
@@ -85,5 +82,4 @@
messageBuilder.append(getNumberRelatedMessage());
return messageBuilder.toString();
}
-
}
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index 324362a..626e5cc 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -68,6 +68,25 @@
return flags;
}
+ public boolean isMoreVisibleThan(AccessFlags other) {
+ return visibilityOrdinal() > other.visibilityOrdinal();
+ }
+
+ private int visibilityOrdinal() {
+ // public > protected > package > private
+ if (isPublic()) {
+ return 3;
+ }
+ if (isProtected()) {
+ return 2;
+ }
+ if (isPrivate()) {
+ return 0;
+ }
+ // Package-private
+ return 1;
+ }
+
public boolean isPublic() {
return isSet(Constants.ACC_PUBLIC);
}
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 6e93a90..1fd4a73 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfLabel;
@@ -201,11 +200,7 @@
@Override
public IRCode buildIR(
- DexEncodedMethod encodedMethod,
- AppInfo appInfo,
- InternalOptions options,
- Origin origin)
- throws ApiLevelException {
+ DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
return internalBuild(encodedMethod, appInfo, options, null, null, origin);
}
@@ -216,8 +211,7 @@
InternalOptions options,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin)
- throws ApiLevelException {
+ Origin origin) {
assert valueNumberGenerator != null;
assert callerPosition != null;
return internalBuild(
@@ -230,8 +224,7 @@
InternalOptions options,
ValueNumberGenerator generator,
Position callerPosition,
- Origin origin)
- throws ApiLevelException {
+ Origin origin) {
assert !options.isGeneratingDex() || !encodedMethod.accessFlags.isSynchronized()
: "Converting CfCode to IR not supported for DEX output of synchronized methods.";
CfSourceCode source = new CfSourceCode(this, encodedMethod, callerPosition, origin);
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 6f86412..60a5ef5 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
@@ -18,11 +17,7 @@
public abstract class Code extends CachedHashValueDexItem {
public abstract IRCode buildIR(
- DexEncodedMethod encodedMethod,
- AppInfo appInfo,
- InternalOptions options,
- Origin origin)
- throws ApiLevelException;
+ DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin);
public IRCode buildInliningIR(
DexEncodedMethod encodedMethod,
@@ -30,8 +25,7 @@
InternalOptions options,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin)
- throws ApiLevelException {
+ Origin origin) {
throw new Unreachable("Unexpected attempt to build IR graph for inlining from: "
+ getClass().getCanonicalName());
}
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 685f32e..b1b5f8a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.ReturnVoid;
import com.android.tools.r8.code.SwitchPayload;
@@ -164,9 +163,8 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, AppInfo appInfo,
- InternalOptions options, Origin origin)
- throws ApiLevelException {
+ public IRCode buildIR(
+ DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
DexSourceCode source =
new DexSourceCode(
this, encodedMethod, null, options.lineNumberOptimization == LineNumberOptimization.ON);
@@ -177,11 +175,11 @@
@Override
public IRCode buildInliningIR(
DexEncodedMethod encodedMethod,
- AppInfo appInfo, InternalOptions options,
+ AppInfo appInfo,
+ InternalOptions options,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin)
- throws ApiLevelException {
+ Origin origin) {
DexSourceCode source =
new DexSourceCode(
this,
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index ee29ff3..9f97f88 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -9,7 +9,6 @@
import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_SUBCLASS;
import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfThrow;
@@ -100,6 +99,7 @@
private Code code;
private CompilationState compilationState = CompilationState.NOT_PROCESSED;
private OptimizationInfo optimizationInfo = DefaultOptimizationInfo.DEFAULT;
+ private int classFileVersion = -1;
public DexEncodedMethod(
DexMethod method,
@@ -115,6 +115,17 @@
assert code == null || !accessFlags.isAbstract();
}
+ public DexEncodedMethod(
+ DexMethod method,
+ MethodAccessFlags flags,
+ DexAnnotationSet annotationSet,
+ ParameterAnnotationsList annotationsList,
+ Code code,
+ int classFileVersion) {
+ this(method, flags, annotationSet, annotationsList, code);
+ this.classFileVersion = classFileVersion;
+ }
+
public boolean isProcessed() {
return compilationState != CompilationState.NOT_PROCESSED;
}
@@ -231,23 +242,21 @@
compilationState = CompilationState.NOT_PROCESSED;
}
- public IRCode buildIR(
- AppInfo appInfo, InternalOptions options, Origin origin) throws ApiLevelException {
+ public IRCode buildIR(AppInfo appInfo, InternalOptions options, Origin origin) {
return code == null ? null : code.buildIR(this, appInfo, options, origin);
}
public IRCode buildInliningIRForTesting(
- InternalOptions options, ValueNumberGenerator valueNumberGenerator)
- throws ApiLevelException {
+ InternalOptions options, ValueNumberGenerator valueNumberGenerator) {
return buildInliningIR(null, options, valueNumberGenerator, null, Origin.unknown());
}
public IRCode buildInliningIR(
- AppInfo appInfo, InternalOptions options,
+ AppInfo appInfo,
+ InternalOptions options,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin)
- throws ApiLevelException {
+ Origin origin) {
return code.buildInliningIR(
this, appInfo, options, valueNumberGenerator, callerPosition, origin);
}
@@ -306,6 +315,21 @@
return code.asDexCode().hasDebugPositions();
}
+ public int getClassFileVersion() {
+ assert classFileVersion >= 0;
+ return classFileVersion;
+ }
+
+ public boolean hasClassFileVersion() {
+ return classFileVersion >= 0;
+ }
+
+ public void upgradeClassFileVersion(int version) {
+ assert version >= 0;
+ assert !hasClassFileVersion() || version >= getClassFileVersion();
+ classFileVersion = version;
+ }
+
public String qualifiedName() {
return method.qualifiedName();
}
@@ -756,6 +780,16 @@
return optimizationInfo;
}
+ public void copyMetadataFromInlinee(DexEncodedMethod inlinee) {
+ // Record that the current method uses identifier name string if the inlinee did so.
+ if (inlinee.getOptimizationInfo().useIdentifierNameString()) {
+ markUseIdentifierNameString();
+ }
+ if (inlinee.classFileVersion > classFileVersion) {
+ upgradeClassFileVersion(inlinee.getClassFileVersion());
+ }
+ }
+
private static Builder builder(DexEncodedMethod from) {
return new Builder(from);
}
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 86ca12a..4e4a78f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -230,6 +230,10 @@
public final DexType annotationThrows = createType("Ldalvik/annotation/Throws;");
public final DexType annotationSynthesizedClassMap =
createType("Lcom/android/tools/r8/annotations/SynthesizedClassMap;");
+ public final DexType annotationCovariantReturnType =
+ createType("Ldalvik/annotation/codegen/CovariantReturnType;");
+ public final DexType annotationCovariantReturnTypes =
+ createType("Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;");
private static final String METAFACTORY_METHOD_NAME = "metafactory";
private static final String METAFACTORY_ALT_METHOD_NAME = "altMetafactory";
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index c1b843f..0a33000 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -356,9 +356,14 @@
}
public void setClassFileVersion(int classFileVersion) {
+ assert classFileVersion >= 0;
this.classFileVersion = classFileVersion;
}
+ public boolean hasClassFileVersion() {
+ return classFileVersion >= 0;
+ }
+
public int getClassFileVersion() {
assert classFileVersion != -1;
return classFileVersion;
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 02f0801..64ba508 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static org.objectweb.asm.ClassReader.SKIP_CODE;
import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
import static org.objectweb.asm.Opcodes.ACC_DEPRECATED;
import static org.objectweb.asm.Opcodes.ASM6;
@@ -90,7 +91,7 @@
ClassReader reader = new ClassReader(input);
reader.accept(
new CreateDexClassVisitor(origin, classKind, reader.b, application, classConsumer),
- SKIP_FRAMES);
+ SKIP_FRAMES | SKIP_CODE);
}
private static int cleanAccessFlags(int access) {
@@ -560,6 +561,11 @@
@Override
public void visitCode() {
+ throw new Unreachable("visitCode() should not be called when SKIP_CODE is set");
+ }
+
+ @Override
+ public void visitEnd() {
if (!flags.isAbstract() && !flags.isNative() && parent.classKind == ClassKind.PROGRAM) {
if (parent.application.options.enableCfFrontend) {
code = new LazyCfCode(method, parent.origin, parent.context, parent.application);
@@ -567,12 +573,6 @@
code = new JarCode(method, parent.origin, parent.context, parent.application);
}
}
- }
-
- @Override
- public void visitEnd() {
- assert flags.isAbstract() || flags.isNative() || parent.classKind != ClassKind.PROGRAM
- || code != null;
ParameterAnnotationsList annotationsList;
if (parameterAnnotationsLists == null) {
annotationsList = ParameterAnnotationsList.empty();
@@ -595,8 +595,14 @@
parameterFlags.toArray(new DexValue[parameterFlags.size()]),
parent.application.getFactory()));
}
- DexEncodedMethod dexMethod = new DexEncodedMethod(method, flags,
- createAnnotationSet(annotations), annotationsList, code);
+ DexEncodedMethod dexMethod =
+ new DexEncodedMethod(
+ method,
+ flags,
+ createAnnotationSet(annotations),
+ annotationsList,
+ code,
+ parent.version);
if (flags.isStatic() || flags.isConstructor() || flags.isPrivate()) {
parent.directMethods.add(dexMethod);
} else {
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 3bd4cde..640172f 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.InvalidDebugInfoException;
import com.android.tools.r8.graph.JarClassFileReader.ReparseContext;
import com.android.tools.r8.ir.code.IRCode;
@@ -104,9 +103,8 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, AppInfo appInfo,
- InternalOptions options, Origin origin)
- throws ApiLevelException {
+ public IRCode buildIR(
+ DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
triggerDelayedParsingIfNeccessary();
return options.debug
? internalBuildWithLocals(encodedMethod, appInfo, options, null, null)
@@ -116,11 +114,11 @@
@Override
public IRCode buildInliningIR(
DexEncodedMethod encodedMethod,
- AppInfo appInfo, InternalOptions options,
+ AppInfo appInfo,
+ InternalOptions options,
ValueNumberGenerator generator,
Position callerPosition,
- Origin origin)
- throws ApiLevelException {
+ Origin origin) {
assert generator != null;
triggerDelayedParsingIfNeccessary();
return options.debug
@@ -130,10 +128,10 @@
private IRCode internalBuildWithLocals(
DexEncodedMethod encodedMethod,
- AppInfo appInfo, InternalOptions options,
+ AppInfo appInfo,
+ InternalOptions options,
ValueNumberGenerator generator,
- Position callerPosition)
- throws ApiLevelException {
+ Position callerPosition) {
try {
return internalBuild(encodedMethod, appInfo, options, generator, callerPosition);
} catch (InvalidDebugInfoException e) {
@@ -145,10 +143,10 @@
private IRCode internalBuild(
DexEncodedMethod encodedMethod,
- AppInfo appInfo, InternalOptions options,
+ AppInfo appInfo,
+ InternalOptions options,
ValueNumberGenerator generator,
- Position callerPosition)
- throws ApiLevelException {
+ Position callerPosition) {
if (!options.debug) {
node.localVariables.clear();
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index bd6d3f7..8ecc1ab 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.code.CfArithmeticBinop;
import com.android.tools.r8.cf.code.CfArrayLength;
import com.android.tools.r8.cf.code.CfArrayLoad;
@@ -175,9 +174,8 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, AppInfo appInfo,
- InternalOptions options, Origin origin)
- throws ApiLevelException {
+ public IRCode buildIR(
+ DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
return asCfCode().buildIR(encodedMethod, appInfo, options, origin);
}
@@ -188,8 +186,7 @@
InternalOptions options,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin)
- throws ApiLevelException {
+ Origin origin) {
return asCfCode().buildInliningIR(
encodedMethod, appInfo, options, valueNumberGenerator, callerPosition, origin);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 382a0a9..e68e3d5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -5,7 +5,6 @@
import static it.unimi.dsi.fastutil.ints.Int2ObjectSortedMaps.emptyMap;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
@@ -359,8 +358,7 @@
@Override
public void buildInstruction(
- IRBuilder builder, int instructionIndex, boolean firstBlockInstruction)
- throws ApiLevelException {
+ IRBuilder builder, int instructionIndex, boolean firstBlockInstruction) {
CfInstruction instruction = code.getInstructions().get(instructionIndex);
currentInstructionIndex = instructionIndex;
if (firstBlockInstruction) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 0d87723..31ee706 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.conversion;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.code.FillArrayData;
import com.android.tools.r8.code.FillArrayDataPayload;
import com.android.tools.r8.code.FilledNewArray;
@@ -173,8 +172,7 @@
@Override
public void buildInstruction(
- IRBuilder builder, int instructionIndex, boolean firstBlockInstruction)
- throws ApiLevelException {
+ IRBuilder builder, int instructionIndex, boolean firstBlockInstruction) {
updateCurrentCatchHandlers(instructionIndex);
updateDebugPosition(instructionIndex, builder);
currentDexInstruction = code.instructions[instructionIndex];
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index c697105..702218e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -357,7 +357,7 @@
*
* @return The list of basic blocks. First block is the main entry.
*/
- public IRCode build() throws ApiLevelException {
+ public IRCode build() {
assert source != null;
source.setUp();
@@ -516,7 +516,7 @@
return true;
}
- private void processWorklist() throws ApiLevelException {
+ private void processWorklist() {
for (WorklistItem item = ssaWorklist.poll(); item != null; item = ssaWorklist.poll()) {
if (item.block.isFilled()) {
continue;
@@ -835,8 +835,7 @@
add(instruction);
}
- public void addConstMethodHandle(int dest, DexMethodHandle methodHandle)
- throws ApiLevelException {
+ public void addConstMethodHandle(int dest, DexMethodHandle methodHandle) {
if (!options.canUseConstantMethodHandle()) {
throw new ApiLevelException(
AndroidApiLevel.P,
@@ -848,8 +847,7 @@
add(instruction);
}
- public void addConstMethodType(int dest, DexProto methodType)
- throws ApiLevelException {
+ public void addConstMethodType(int dest, DexProto methodType) {
if (!options.canUseConstantMethodType()) {
throw new ApiLevelException(
AndroidApiLevel.P,
@@ -1040,8 +1038,7 @@
}
public void addInvoke(
- Type type, DexItem item, DexProto callSiteProto, List<Value> arguments, boolean itf)
- throws ApiLevelException {
+ Type type, DexItem item, DexProto callSiteProto, List<Value> arguments, boolean itf) {
if (type == Type.POLYMORPHIC) {
assert item instanceof DexMethod;
if (!options.canUseInvokePolymorphic()) {
@@ -1073,8 +1070,7 @@
add(Invoke.create(type, item, callSiteProto, null, arguments, itf));
}
- public void addInvoke(Type type, DexItem item, DexProto callSiteProto, List<Value> arguments)
- throws ApiLevelException {
+ public void addInvoke(Type type, DexItem item, DexProto callSiteProto, List<Value> arguments) {
addInvoke(type, item, callSiteProto, arguments, false);
}
@@ -1083,8 +1079,7 @@
DexItem item,
DexProto callSiteProto,
List<ValueType> types,
- List<Integer> registers)
- throws ApiLevelException {
+ List<Integer> registers) {
addInvoke(type, item, callSiteProto, types, registers, false);
}
@@ -1094,8 +1089,7 @@
DexProto callSiteProto,
List<ValueType> types,
List<Integer> registers,
- boolean itf)
- throws ApiLevelException {
+ boolean itf) {
assert types.size() == registers.size();
List<Value> arguments = new ArrayList<>(types.size());
for (int i = 0; i < types.size(); i++) {
@@ -1163,8 +1157,7 @@
DexMethod method,
DexProto callSiteProto,
int argumentRegisterCount,
- int[] argumentRegisters)
- throws ApiLevelException {
+ int[] argumentRegisters) {
// The value of argumentRegisterCount is the number of registers - not the number of values,
// but it is an upper bound on the number of arguments.
List<Value> arguments = new ArrayList<>(argumentRegisterCount);
@@ -1191,8 +1184,7 @@
addInvoke(type, method, callSiteProto, arguments);
}
- public void addInvokeNewArray(DexType type, int argumentCount, int[] argumentRegisters)
- throws ApiLevelException {
+ public void addInvokeNewArray(DexType type, int argumentCount, int[] argumentRegisters) {
String descriptor = type.descriptor.toString();
assert descriptor.charAt(0) == '[';
assert descriptor.length() >= 2;
@@ -1211,7 +1203,7 @@
addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments);
}
- public void addMultiNewArray(DexType type, int dest, int[] dimensions) throws ApiLevelException {
+ public void addMultiNewArray(DexType type, int dest, int[] dimensions) {
assert isGeneratingClassFiles();
List<Value> arguments = new ArrayList<>(dimensions.length);
for (int dimension : dimensions) {
@@ -1226,8 +1218,7 @@
DexMethod method,
DexProto callSiteProto,
int argumentCount,
- int firstArgumentRegister)
- throws ApiLevelException {
+ int firstArgumentRegister) {
// The value of argumentCount is the number of registers - not the number of values, but it
// is an upper bound on the number of arguments.
List<Value> arguments = new ArrayList<>(argumentCount);
@@ -1254,8 +1245,7 @@
addInvoke(type, method, callSiteProto, arguments);
}
- public void addInvokeRangeNewArray(DexType type, int argumentCount, int firstArgumentRegister)
- throws ApiLevelException {
+ public void addInvokeRangeNewArray(DexType type, int argumentCount, int firstArgumentRegister) {
String descriptor = type.descriptor.toString();
assert descriptor.charAt(0) == '[';
assert descriptor.length() >= 2;
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 8477d9b..90a9898 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
@@ -6,7 +6,6 @@
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
@@ -33,6 +32,7 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.ir.desugar.StringConcatRewriter;
@@ -100,6 +100,7 @@
private final ProtoLitePruner protoLiteRewriter;
private final IdentifierNameStringMarker identifierNameStringMarker;
private final Devirtualizer devirtualizer;
+ private final CovariantReturnTypeAnnotationTransformer covariantReturnTypeAnnotationTransformer;
private final OptimizationFeedback ignoreOptimizationFeedback = new OptimizationFeedbackIgnore();
private DexString highestSortingString;
@@ -127,6 +128,10 @@
? new InterfaceMethodRewriter(this, options) : null;
this.lambdaMerger = options.enableLambdaMerging
? new LambdaMerger(appInfo.dexItemFactory, options.reporter) : null;
+ this.covariantReturnTypeAnnotationTransformer =
+ options.processCovariantReturnTypeAnnotations
+ ? new CovariantReturnTypeAnnotationTransformer(this, appInfo.dexItemFactory)
+ : null;
if (enableWholeProgramOptimizations) {
assert appInfo.hasLiveness();
this.nonNullTracker = new NonNullTracker();
@@ -233,7 +238,7 @@
}
}
- private void synthesizeLambdaClasses(Builder<?> builder) throws ApiLevelException {
+ private void synthesizeLambdaClasses(Builder<?> builder) {
if (lambdaRewriter != null) {
lambdaRewriter.adjustAccessibility();
lambdaRewriter.synthesizeLambdaClasses(builder);
@@ -241,15 +246,20 @@
}
private void desugarInterfaceMethods(
- Builder<?> builder, InterfaceMethodRewriter.Flavor includeAllResources)
- throws ApiLevelException {
+ Builder<?> builder, InterfaceMethodRewriter.Flavor includeAllResources) {
if (interfaceMethodRewriter != null) {
interfaceMethodRewriter.desugarInterfaceMethods(builder, includeAllResources);
}
}
+ private void processCovariantReturnTypeAnnotations(Builder<?> builder) {
+ if (covariantReturnTypeAnnotationTransformer != null) {
+ covariantReturnTypeAnnotationTransformer.process(builder);
+ }
+ }
+
public DexApplication convertToDex(DexApplication application, ExecutorService executor)
- throws ExecutionException, ApiLevelException {
+ throws ExecutionException {
removeLambdaDeserializationMethods();
timing.begin("IR conversion");
@@ -261,6 +271,7 @@
synthesizeLambdaClasses(builder);
desugarInterfaceMethods(builder, ExcludeDexResources);
+ processCovariantReturnTypeAnnotations(builder);
handleSynthesizedClassMapping(builder);
timing.end();
@@ -347,7 +358,7 @@
ThreadUtils.awaitFutures(futures);
}
- void convertMethodToDex(DexEncodedMethod method) throws ApiLevelException {
+ void convertMethodToDex(DexEncodedMethod method) {
assert options.isGeneratingDex();
if (method.getCode() != null) {
boolean matchesMethodFilter = options.methodMatchesFilter(method);
@@ -362,8 +373,7 @@
}
}
- public DexApplication optimize(DexApplication application)
- throws ExecutionException, ApiLevelException {
+ public DexApplication optimize(DexApplication application) throws ExecutionException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
return optimize(application, executor);
@@ -372,9 +382,8 @@
}
}
- public DexApplication optimize(DexApplication application,
- ExecutorService executorService)
- throws ExecutionException, ApiLevelException {
+ public DexApplication optimize(DexApplication application, ExecutorService executorService)
+ throws ExecutionException {
removeLambdaDeserializationMethods();
collectLambdaMergingCandidates(application);
@@ -392,10 +401,14 @@
.build(application, appInfo.withLiveness(), graphLense, options);
timing.end();
timing.begin("IR conversion phase 1");
- callGraph.forEachMethod((method, isProcessedConcurrently) -> {
- processMethod(method, directFeedback, isProcessedConcurrently, callGraph,
- outliner == null ? Outliner::noProcessing : outliner::identifyCandidates);
- }, executorService);
+ BiConsumer<IRCode, DexEncodedMethod> outlineHandler =
+ outliner == null ? Outliner::noProcessing : outliner.identifyCandidateMethods();
+ callGraph.forEachMethod(
+ (method, isProcessedConcurrently) -> {
+ processMethod(
+ method, directFeedback, isProcessedConcurrently, callGraph, outlineHandler);
+ },
+ executorService);
timing.end();
}
@@ -418,25 +431,23 @@
if (outliner != null) {
timing.begin("IR conversion phase 2");
- // Compile all classes flagged for outlining and
- // add the outline support class IF needed.
- DexProgramClass outlineClass = prepareOutlining();
- if (outlineClass != null) {
- // We need a new call graph to ensure deterministic order and also processing inside out
- // to get maximal inlining. Use a identity lense, as the code has been rewritten.
- CallGraph callGraph = CallGraph
- .build(application, appInfo.withLiveness(), GraphLense.getIdentityLense(), options);
- Set<DexEncodedMethod> outlineMethods = outliner.getMethodsSelectedForOutlining();
- callGraph.forEachMethod((method, isProcessedConcurrently) -> {
- if (!outlineMethods.contains(method)) {
- return;
- }
- // This is the second time we compile this method first mark it not processed.
- assert !method.getCode().isOutlineCode();
- processMethod(method, ignoreOptimizationFeedback, isProcessedConcurrently, callGraph,
- outliner::applyOutliningCandidate);
- assert method.isProcessed();
- }, executorService);
+ if (outliner.selectMethodsForOutlining()) {
+ forEachSelectedOutliningMethod(
+ executorService,
+ (code, method) -> {
+ printMethod(code, "IR before outlining (SSA)");
+ outliner.identifyOutlineSites(code, method);
+ });
+ DexProgramClass outlineClass = outliner.buildOutlinerClass(computeOutlineClassType());
+ optimizeSynthesizedClass(outlineClass);
+ forEachSelectedOutliningMethod(
+ executorService,
+ (code, method) -> {
+ outliner.applyOutliningCandidate(code, method);
+ printMethod(code, "IR after outlining (SSA)");
+ finalizeIR(method, code, ignoreOptimizationFeedback);
+ });
+ assert outliner.checkAllOutlineSitesFoundAgain();
builder.addSynthesizedClass(outlineClass, true);
clearDexMethodCompilationState(outlineClass);
}
@@ -451,15 +462,45 @@
return builder.build();
}
+ private void forEachSelectedOutliningMethod(
+ ExecutorService executorService, BiConsumer<IRCode, DexEncodedMethod> consumer)
+ throws ExecutionException {
+ assert !options.skipIR;
+ Set<DexEncodedMethod> methods = outliner.getMethodsSelectedForOutlining();
+ List<Future<?>> futures = new ArrayList<>();
+ for (DexEncodedMethod method : methods) {
+ futures.add(
+ executorService.submit(
+ () -> {
+ IRCode code =
+ method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
+ assert code != null;
+ assert !method.getCode().isOutlineCode();
+ // Instead of repeating all the optimizations of rewriteCode(), only run the
+ // optimizations needed for outlining: rewriteMoveResult() to remove out-values on
+ // StringBuilder/StringBuffer method invocations, and removeDeadCode() to remove
+ // unused out-values.
+ codeRewriter.rewriteMoveResult(code);
+ DeadCodeRemover.removeDeadCode(code, codeRewriter, options);
+ consumer.accept(code, method);
+ return null;
+ }));
+ }
+ ThreadUtils.awaitFutures(futures);
+ }
+
private void collectLambdaMergingCandidates(DexApplication application) {
if (lambdaMerger != null) {
lambdaMerger.collectGroupCandidates(application, appInfo.withLiveness(), options);
}
}
- private void finalizeLambdaMerging(DexApplication application,
- OptimizationFeedback directFeedback, Builder<?> builder, ExecutorService executorService)
- throws ExecutionException, ApiLevelException {
+ private void finalizeLambdaMerging(
+ DexApplication application,
+ OptimizationFeedback directFeedback,
+ Builder<?> builder,
+ ExecutorService executorService)
+ throws ExecutionException {
if (lambdaMerger != null) {
lambdaMerger.applyLambdaClassMapping(
application, this, directFeedback, builder, executorService);
@@ -512,16 +553,7 @@
return result;
}
- private DexProgramClass prepareOutlining() throws ApiLevelException {
- if (!outliner.selectMethodsForOutlining()) {
- return null;
- }
- DexProgramClass outlineClass = outliner.buildOutlinerClass(computeOutlineClassType());
- optimizeSynthesizedClass(outlineClass);
- return outlineClass;
- }
-
- public void optimizeSynthesizedClass(DexProgramClass clazz) throws ApiLevelException {
+ public void optimizeSynthesizedClass(DexProgramClass clazz) {
try {
codeRewriter.enterCachedClass(clazz);
// Process the generated class, but don't apply any outlining.
@@ -531,7 +563,7 @@
}
}
- public void optimizeSynthesizedMethod(DexEncodedMethod method) throws ApiLevelException {
+ public void optimizeSynthesizedMethod(DexEncodedMethod method) {
// Process the generated method, but don't apply any outlining.
processMethod(method, ignoreOptimizationFeedback, x -> false, CallSiteInformation.empty(),
Outliner::noProcessing);
@@ -541,12 +573,12 @@
return options.useSmaliSyntax ? method.toSmaliString(null) : method.codeToString();
}
- public void processMethod(DexEncodedMethod method,
+ public void processMethod(
+ DexEncodedMethod method,
OptimizationFeedback feedback,
Predicate<DexEncodedMethod> isProcessedConcurrently,
CallSiteInformation callSiteInformation,
- BiConsumer<IRCode, DexEncodedMethod> outlineHandler)
- throws ApiLevelException {
+ BiConsumer<IRCode, DexEncodedMethod> outlineHandler) {
Code code = method.getCode();
boolean matchesMethodFilter = options.methodMatchesFilter(method);
if (code != null && matchesMethodFilter) {
@@ -565,12 +597,12 @@
}
}
- private void rewriteCode(DexEncodedMethod method,
+ private void rewriteCode(
+ DexEncodedMethod method,
OptimizationFeedback feedback,
Predicate<DexEncodedMethod> isProcessedConcurrently,
CallSiteInformation callSiteInformation,
- BiConsumer<IRCode, DexEncodedMethod> outlineHandler)
- throws ApiLevelException {
+ BiConsumer<IRCode, DexEncodedMethod> outlineHandler) {
if (options.verbose) {
options.reporter.info(
new StringDiagnostic("Processing: " + method.toSourceString()));
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 46cc8e9..b5f0a05 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
@@ -29,7 +28,6 @@
import com.android.tools.r8.ir.conversion.JarState.Local;
import com.android.tools.r8.ir.conversion.JarState.Slot;
import com.android.tools.r8.logging.Log;
-import com.android.tools.r8.utils.ThrowingBiConsumer;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
@@ -44,6 +42,7 @@
import java.util.List;
import java.util.Queue;
import java.util.Set;
+import java.util.function.BiConsumer;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -478,8 +477,7 @@
@Override
public void buildInstruction(
- IRBuilder builder, int instructionIndex, boolean firstBlockInstruction)
- throws ApiLevelException {
+ IRBuilder builder, int instructionIndex, boolean firstBlockInstruction) {
if (instructionIndex == EXCEPTIONAL_SYNC_EXIT_OFFSET) {
buildExceptionalPostlude(builder);
return;
@@ -1816,7 +1814,7 @@
// IR instruction building procedures.
- private void build(AbstractInsnNode insn, IRBuilder builder) throws ApiLevelException {
+ private void build(AbstractInsnNode insn, IRBuilder builder) {
switch (insn.getType()) {
case AbstractInsnNode.INSN:
build((InsnNode) insn, builder);
@@ -2540,7 +2538,7 @@
}
}
- private void build(MethodInsnNode insn, IRBuilder builder) throws ApiLevelException {
+ private void build(MethodInsnNode insn, IRBuilder builder) {
// Resolve the target method of the invoke.
DexMethod method = application.getMethod(insn.owner, insn.name, insn.desc);
@@ -2619,8 +2617,7 @@
Type methodOwner,
boolean addImplicitReceiver,
IRBuilder builder,
- ThrowingBiConsumer<List<ValueType>, List<Integer>, ApiLevelException> creator)
- throws ApiLevelException {
+ BiConsumer<List<ValueType>, List<Integer>> creator) {
// Build the argument list of the form [owner, param1, ..., paramN].
// The arguments are in reverse order on the stack, so we pop off the parameters here.
@@ -2657,7 +2654,7 @@
registers.add(slot.register);
}
- private void build(InvokeDynamicInsnNode insn, IRBuilder builder) throws ApiLevelException {
+ private void build(InvokeDynamicInsnNode insn, IRBuilder builder) {
DexCallSite callSite = DexCallSite.fromAsmInvokeDynamic(insn, application, clazz);
buildInvoke(insn.desc, null /* Not needed */,
@@ -2716,7 +2713,7 @@
// Intentionally empty.
}
- private void build(LdcInsnNode insn, IRBuilder builder) throws ApiLevelException {
+ private void build(LdcInsnNode insn, IRBuilder builder) {
if (insn.cst instanceof Type) {
Type type = (Type) insn.cst;
if (type.getSort() == Type.METHOD) {
@@ -2781,7 +2778,7 @@
builder.addSwitch(index, keys, fallthroughOffset, labelOffsets);
}
- private void build(MultiANewArrayInsnNode insn, IRBuilder builder) throws ApiLevelException {
+ private void build(MultiANewArrayInsnNode insn, IRBuilder builder) {
// Type of the full array.
Type arrayType = application.getAsmObjectType(insn.desc);
DexType dexArrayType = application.getType(arrayType);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java
index cd8efa7..e95790a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/SourceCode.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.conversion;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Position;
@@ -48,8 +47,8 @@
// Delegates for IR building.
void buildPrelude(IRBuilder builder);
- void buildInstruction(IRBuilder builder, int instructionIndex, boolean firstBlockInstruction)
- throws ApiLevelException;
+ void buildInstruction(IRBuilder builder, int instructionIndex, boolean firstBlockInstruction);
+
void buildPostlude(IRBuilder builder);
// Helper to resolve switch payloads and build switch instructions (dex code only).
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
new file mode 100644
index 0000000..5b397e0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
@@ -0,0 +1,266 @@
+// 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.ir.desugar;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotationElement;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
+import com.android.tools.r8.ir.synthetic.SynthesizedCode;
+import com.google.common.base.Predicates;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+// Responsible for processing the annotations dalvik.annotation.codegen.CovariantReturnType and
+// dalvik.annotation.codegen.CovariantReturnType$CovariantReturnTypes.
+//
+// Consider the following class:
+// public class B extends A {
+// @CovariantReturnType(returnType = B.class, presentAfter = 25)
+// @Override
+// public A m(...) { ... return new B(); }
+// }
+//
+// The annotation is used to indicate that the compiler should insert a synthetic method that is
+// equivalent to method m, but has return type B instead of A. Thus, for this example, this
+// component is responsible for inserting the following method in class B (in addition to the
+// existing method m):
+// public B m(...) { A result = "invoke B.m(...)A;"; return (B) result; }
+//
+// Note that a method may be annotated with more than one CovariantReturnType annotation. In this
+// case there will be a CovariantReturnType$CovariantReturnTypes annotation on the method that wraps
+// several CovariantReturnType annotations. In this case, a new method is synthesized for each of
+// the contained CovariantReturnType annotations.
+public final class CovariantReturnTypeAnnotationTransformer {
+ private final IRConverter converter;
+ private final DexItemFactory factory;
+
+ public CovariantReturnTypeAnnotationTransformer(IRConverter converter, DexItemFactory factory) {
+ this.converter = converter;
+ this.factory = factory;
+ }
+
+ public void process(DexApplication.Builder<?> builder) {
+ // List of methods that should be added to the next class.
+ List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation = new LinkedList<>();
+ List<DexEncodedMethod> covariantReturnTypeMethods = new LinkedList<>();
+ for (DexClass clazz : builder.getProgramClasses()) {
+ // Construct the methods that should be added to clazz.
+ buildCovariantReturnTypeMethodsForClass(
+ clazz, methodsWithCovariantReturnTypeAnnotation, covariantReturnTypeMethods);
+ if (covariantReturnTypeMethods.isEmpty()) {
+ continue;
+ }
+ updateClass(clazz, methodsWithCovariantReturnTypeAnnotation, covariantReturnTypeMethods);
+ // Reset lists for the next class that will have a CovariantReturnType or
+ // CovariantReturnType$CovariantReturnTypes annotation.
+ methodsWithCovariantReturnTypeAnnotation.clear();
+ covariantReturnTypeMethods.clear();
+ }
+ }
+
+ private void updateClass(
+ DexClass clazz,
+ List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation,
+ List<DexEncodedMethod> covariantReturnTypeMethods) {
+ // It is a compilation error if the class already has a method with a signature similar to one
+ // of the methods in covariantReturnTypeMethods.
+ for (DexEncodedMethod syntheticMethod : covariantReturnTypeMethods) {
+ if (hasVirtualMethodWithSignature(clazz, syntheticMethod)) {
+ throw new CompilationError(
+ String.format(
+ "Cannot process CovariantReturnType annotation: Class %s already "
+ + "has a method \"%s\"",
+ clazz.getType(), syntheticMethod.toSourceString()));
+ }
+ }
+ // Remove the CovariantReturnType annotations.
+ for (DexEncodedMethod method : methodsWithCovariantReturnTypeAnnotation) {
+ method.annotations =
+ method.annotations.keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation));
+ }
+ // Add the newly constructed methods to the class.
+ DexEncodedMethod[] oldVirtualMethods = clazz.virtualMethods();
+ DexEncodedMethod[] newVirtualMethods =
+ new DexEncodedMethod[oldVirtualMethods.length + covariantReturnTypeMethods.size()];
+ System.arraycopy(oldVirtualMethods, 0, newVirtualMethods, 0, oldVirtualMethods.length);
+ int i = oldVirtualMethods.length;
+ for (DexEncodedMethod syntheticMethod : covariantReturnTypeMethods) {
+ newVirtualMethods[i] = syntheticMethod;
+ i++;
+ }
+ clazz.setVirtualMethods(newVirtualMethods);
+ }
+
+ // Processes all the dalvik.annotation.codegen.CovariantReturnType and dalvik.annotation.codegen.
+ // CovariantReturnTypes annotations in the given DexClass. Adds the newly constructed, synthetic
+ // methods to the list covariantReturnTypeMethods.
+ private void buildCovariantReturnTypeMethodsForClass(
+ DexClass clazz,
+ List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation,
+ List<DexEncodedMethod> covariantReturnTypeMethods) {
+ for (DexEncodedMethod method : clazz.virtualMethods()) {
+ if (methodHasCovariantReturnTypeAnnotation(method)) {
+ methodsWithCovariantReturnTypeAnnotation.add(method);
+ buildCovariantReturnTypeMethodsForMethod(clazz, method, covariantReturnTypeMethods);
+ }
+ }
+ }
+
+ private boolean methodHasCovariantReturnTypeAnnotation(DexEncodedMethod method) {
+ for (DexAnnotation annotation : method.annotations.annotations) {
+ if (isCovariantReturnTypeAnnotation(annotation.annotation)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Processes all the dalvik.annotation.codegen.CovariantReturnType and dalvik.annotation.Co-
+ // variantReturnTypes annotations on the given method. Adds the newly constructed, synthetic
+ // methods to the list covariantReturnTypeMethods.
+ private void buildCovariantReturnTypeMethodsForMethod(
+ DexClass clazz, DexEncodedMethod method, List<DexEncodedMethod> covariantReturnTypeMethods) {
+ assert methodHasCovariantReturnTypeAnnotation(method);
+ for (DexType covariantReturnType : getCovariantReturnTypes(clazz, method)) {
+ DexEncodedMethod covariantReturnTypeMethod =
+ buildCovariantReturnTypeMethod(clazz, method, covariantReturnType);
+ covariantReturnTypeMethods.add(covariantReturnTypeMethod);
+ }
+ }
+
+ // Builds a synthetic method that invokes the given method, casts the result to
+ // covariantReturnType, and then returns the result. The newly created method will have return
+ // type covariantReturnType.
+ //
+ // Note: any "synchronized" or "strictfp" modifier could be dropped safely.
+ private DexEncodedMethod buildCovariantReturnTypeMethod(
+ DexClass clazz, DexEncodedMethod method, DexType covariantReturnType) {
+ DexProto newProto =
+ factory.createProto(
+ covariantReturnType, method.method.proto.shorty, method.method.proto.parameters);
+ MethodAccessFlags newAccessFlags = method.accessFlags.copy();
+ newAccessFlags.setBridge();
+ newAccessFlags.setSynthetic();
+ DexEncodedMethod newVirtualMethod =
+ new DexEncodedMethod(
+ factory.createMethod(method.method.holder, newProto, method.method.name),
+ newAccessFlags,
+ method.annotations.keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation)),
+ method.parameterAnnotationsList.keepIf(Predicates.alwaysTrue()),
+ new SynthesizedCode(
+ new ForwardMethodSourceCode(
+ clazz.type,
+ newProto,
+ method.method.holder,
+ method.method,
+ Invoke.Type.VIRTUAL,
+ true)));
+ // Optimize to generate DexCode instead of SynthesizedCode.
+ converter.optimizeSynthesizedMethod(newVirtualMethod);
+ return newVirtualMethod;
+ }
+
+ // Returns the set of covariant return types for method.
+ //
+ // If the method is:
+ // @dalvik.annotation.codegen.CovariantReturnType(returnType=SubOfFoo, presentAfter=25)
+ // @dalvik.annotation.codegen.CovariantReturnType(returnType=SubOfSubOfFoo, presentAfter=28)
+ // @Override
+ // public Foo foo() { ... return new SubOfSubOfFoo(); }
+ // then this method returns the set { SubOfFoo, SubOfSubOfFoo }.
+ private Set<DexType> getCovariantReturnTypes(DexClass clazz, DexEncodedMethod method) {
+ Set<DexType> covariantReturnTypes = new HashSet<>();
+ for (DexAnnotation annotation : method.annotations.annotations) {
+ if (isCovariantReturnTypeAnnotation(annotation.annotation)) {
+ getCovariantReturnTypesFromAnnotation(
+ clazz, method, annotation.annotation, covariantReturnTypes);
+ }
+ }
+ return covariantReturnTypes;
+ }
+
+ private void getCovariantReturnTypesFromAnnotation(
+ DexClass clazz,
+ DexEncodedMethod method,
+ DexEncodedAnnotation annotation,
+ Set<DexType> covariantReturnTypes) {
+ assert isCovariantReturnTypeAnnotation(annotation);
+ boolean hasPresentAfterElement = false;
+ for (DexAnnotationElement element : annotation.elements) {
+ String name = element.name.toString();
+ if (annotation.type == factory.annotationCovariantReturnType) {
+ if (name.equals("returnType")) {
+ if (!(element.value instanceof DexValue.DexValueType)) {
+ throw new CompilationError(
+ String.format(
+ "Expected element \"returnType\" of CovariantReturnType annotation to "
+ + "reference a type (method: \"%s\", was: %s)",
+ method.toSourceString(), element.value.getClass().getCanonicalName()));
+ }
+
+ DexValue.DexValueType dexValueType = (DexValue.DexValueType) element.value;
+ covariantReturnTypes.add(dexValueType.value);
+ } else if (name.equals("presentAfter")) {
+ hasPresentAfterElement = true;
+ }
+ } else {
+ if (name.equals("value")) {
+ if (!(element.value instanceof DexValue.DexValueArray)) {
+ throw new CompilationError(
+ String.format(
+ "Expected element \"value\" of CovariantReturnTypes annotation to "
+ + "be an array (method: \"%s\", was: %s)",
+ method.toSourceString(), element.value.getClass().getCanonicalName()));
+ }
+
+ DexValue.DexValueArray array = (DexValue.DexValueArray) element.value;
+ // Handle the inner dalvik.annotation.codegen.CovariantReturnType annotations recursively.
+ for (DexValue value : array.getValues()) {
+ assert value instanceof DexValue.DexValueAnnotation;
+ DexValue.DexValueAnnotation innerAnnotation = (DexValue.DexValueAnnotation) value;
+ getCovariantReturnTypesFromAnnotation(
+ clazz, method, innerAnnotation.value, covariantReturnTypes);
+ }
+ }
+ }
+ }
+
+ if (annotation.type == factory.annotationCovariantReturnType && !hasPresentAfterElement) {
+ throw new CompilationError(
+ String.format(
+ "CovariantReturnType annotation for method \"%s\" is missing mandatory element "
+ + "\"presentAfter\" (class %s)",
+ clazz.getType(), method.toSourceString()));
+ }
+ }
+
+ private boolean isCovariantReturnTypeAnnotation(DexEncodedAnnotation annotation) {
+ return annotation.type == factory.annotationCovariantReturnType
+ || annotation.type == factory.annotationCovariantReturnTypes;
+ }
+
+ private static boolean hasVirtualMethodWithSignature(DexClass clazz, DexEncodedMethod method) {
+ for (DexEncodedMethod existingMethod : clazz.virtualMethods()) {
+ if (existingMethod.method.equals(method.method)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 8add960..73c5118 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.desugar;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexApplication.Builder;
@@ -325,7 +324,7 @@
* Move static and default interface methods to companion classes,
* add missing methods to forward to moved default methods implementation.
*/
- public void desugarInterfaceMethods(Builder<?> builder, Flavor flavour) throws ApiLevelException {
+ public void desugarInterfaceMethods(Builder<?> builder, Flavor flavour) {
// Process all classes first. Add missing forwarding methods to
// replace desugared default interface methods.
forwardingMethods.addAll(processClasses(builder, flavour));
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 d9bd4bd..81407bd 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
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.desugar;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
@@ -425,7 +424,7 @@
}
// Ensure access of the referenced symbol(s).
- abstract boolean ensureAccessibility() throws ApiLevelException;
+ abstract boolean ensureAccessibility();
DexClass definitionFor(DexType type) {
return rewriter.converter.appInfo.app.definitionFor(type);
@@ -520,7 +519,7 @@
}
@Override
- boolean ensureAccessibility() throws ApiLevelException {
+ boolean ensureAccessibility() {
// Create a static accessor with proper accessibility.
DexProgramClass accessorClass = programDefinitionFor(callTarget.holder);
assert accessorClass != null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 11ff65b..d6b99a7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.desugar;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication.Builder;
@@ -162,7 +161,7 @@
* Adjust accessibility of referenced application symbols or
* creates necessary accessors.
*/
- public void adjustAccessibility() throws ApiLevelException {
+ public void adjustAccessibility() {
// For each lambda class perform necessary adjustment of the
// referenced symbols to make them accessible. This can result in
// method access relaxation or creation of accessor method.
@@ -172,7 +171,7 @@
}
/** Generates lambda classes and adds them to the builder. */
- public void synthesizeLambdaClasses(Builder<?> builder) throws ApiLevelException {
+ public void synthesizeLambdaClasses(Builder<?> builder) {
for (LambdaClass lambdaClass : knownLambdaClasses.values()) {
DexProgramClass synthesizedClass = lambdaClass.synthesizeLambdaClass();
converter.optimizeSynthesizedClass(synthesizedClass);
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 90081d1..845e17b 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -305,8 +304,7 @@
}
@Override
- public void ensureMethodProcessed(
- DexEncodedMethod target, IRCode inlinee) throws ApiLevelException {
+ public void ensureMethodProcessed(DexEncodedMethod target, IRCode inlinee) {
if (!target.isProcessed()) {
if (Log.ENABLED) {
Log.verbose(getClass(), "Forcing extra inline on " + target.toSourceString());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
index 59ddc36..1b68f7d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
@@ -40,7 +39,7 @@
this.options = options;
}
- public AppInfoWithLiveness run() throws ApiLevelException {
+ public AppInfoWithLiveness run() {
for (DexProgramClass clazz : appInfo.classes()) {
processClasses(clazz);
}
@@ -50,7 +49,7 @@
return appInfo;
}
- private void processClasses(DexProgramClass clazz) throws ApiLevelException {
+ private void processClasses(DexProgramClass clazz) {
// Enum classes are flagged as such. Also, for library classes, the ordinals are not known.
if (!clazz.accessFlags.isEnum() || clazz.isLibraryClass() || !clazz.hasClassInitializer()) {
return;
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 860cc21..b75597d 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexClass;
@@ -151,8 +150,8 @@
return target;
}
- public synchronized void processDoubleInlineCallers(IRConverter converter,
- OptimizationFeedback feedback) throws ApiLevelException {
+ public synchronized void processDoubleInlineCallers(
+ IRConverter converter, OptimizationFeedback feedback) {
if (doubleInlineCallers.size() > 0) {
applyDoubleInlining = true;
List<DexEncodedMethod> methods = doubleInlineCallers
@@ -267,8 +266,7 @@
AppInfoWithSubtyping appInfo,
GraphLense graphLense,
InternalOptions options,
- Position callerPosition)
- throws ApiLevelException {
+ Position callerPosition) {
// Build the IR for a yet not processed method, and perform minimal IR processing.
Origin origin = appInfo.originFor(target.method.holder);
IRCode code = target.buildInliningIR(appInfo, options, generator, callerPosition, origin);
@@ -375,8 +373,10 @@
}
}
- public void performForcedInlining(DexEncodedMethod method, IRCode code,
- Map<InvokeMethodWithReceiver, InliningInfo> invokesToInline) throws ApiLevelException {
+ public void performForcedInlining(
+ DexEncodedMethod method,
+ IRCode code,
+ Map<InvokeMethodWithReceiver, InliningInfo> invokesToInline) {
ForcedInliningOracle oracle = new ForcedInliningOracle(method, invokesToInline);
performInliningImpl(oracle, oracle, method, code);
@@ -387,8 +387,7 @@
IRCode code,
TypeEnvironment typeEnvironment,
Predicate<DexEncodedMethod> isProcessedConcurrently,
- CallSiteInformation callSiteInformation)
- throws ApiLevelException {
+ CallSiteInformation callSiteInformation) {
DefaultInliningOracle oracle =
new DefaultInliningOracle(
@@ -405,11 +404,7 @@
}
private void performInliningImpl(
- InliningStrategy strategy,
- InliningOracle oracle,
- DexEncodedMethod method,
- IRCode code)
- throws ApiLevelException {
+ InliningStrategy strategy, InliningOracle oracle, DexEncodedMethod method, IRCode code) {
if (strategy.exceededAllowance()) {
return;
}
@@ -473,10 +468,7 @@
method.accessFlags.unsetBridge();
}
- // Record that the current method uses identifier name string if the inlinee did so.
- if (target.getOptimizationInfo().useIdentifierNameString()) {
- method.markUseIdentifierNameString();
- }
+ method.copyMetadataFromInlinee(target);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
index 2b0c7e5..7b88b38 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -17,8 +16,7 @@
void markInlined(IRCode inlinee);
- void ensureMethodProcessed(
- DexEncodedMethod target, IRCode inlinee) throws ApiLevelException;
+ void ensureMethodProcessed(DexEncodedMethod target, IRCode inlinee);
ListIterator<BasicBlock> updateTypeInformationIfNeeded(IRCode inlinee,
ListIterator<BasicBlock> blockIterator, BasicBlock block, BasicBlock invokeSuccessor);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 9462354..6cb8f6e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
@@ -64,13 +63,45 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.function.BiConsumer;
+import org.objectweb.asm.Opcodes;
+/**
+ * Support class for implementing outlining (i.e. extracting common code patterns as methods).
+ *
+ * <p>Outlining happens in three steps.
+ *
+ * <ul>
+ * <li>First, all methods are converted to IR and passed to {@link
+ * Outliner#identifyCandidateMethods()} to identify outlining candidates and the methods
+ * containing each candidate. IR is converted to the output format (DEX or CF) and thrown away
+ * along with the outlining candidates; only a list of lists of methods is kept, where each
+ * list of methods corresponds to methods containing an outlining candidate.
+ * <li>Second, {@link Outliner#selectMethodsForOutlining()} is called to retain the lists of
+ * methods found in the first step that are large enough (see {@link InternalOptions#outline}
+ * {@link OutlineOptions#threshold}), and the methods to be further analyzed for outlining is
+ * returned by {@link Outliner#getMethodsSelectedForOutlining}. Each selected method is then
+ * converted back to IR and passed to {@link Outliner#identifyOutlineSites(IRCode,
+ * DexEncodedMethod)}, which then stores concrete outlining candidates in {@link
+ * Outliner#outlineSites}.
+ * <li>Third, {@link Outliner#buildOutlinerClass(DexType)} is called to construct the <em>outline
+ * support class</em> containing a static helper method for each outline candidate that occurs
+ * frequently enough. Each selected method is then converted to IR, passed to {@link
+ * Outliner#applyOutliningCandidate(IRCode, DexEncodedMethod)} to perform the outlining, and
+ * converted back to the output format (DEX or CF).
+ * </ul>
+ */
public class Outliner {
private final InternalOptions options;
- private final Map<Outline, List<DexEncodedMethod>> candidates = new HashMap<>();
- private final Map<Outline, DexMethod> generatedOutlines = new HashMap<>();
+ /** Result of first step (see {@link Outliner#identifyCandidateMethods()}. */
+ private final List<List<DexEncodedMethod>> candidateMethodLists = new ArrayList<>();
+ /** Result of second step (see {@link Outliner#selectMethodsForOutlining()}. */
private final Set<DexEncodedMethod> methodsSelectedForOutlining = Sets.newIdentityHashSet();
+ /** Result of second step (see {@link Outliner#selectMethodsForOutlining()}. */
+ private final Map<Outline, List<DexEncodedMethod>> outlineSites = new HashMap<>();
+ /** Result of third step (see {@link Outliner#buildOutlinerClass(DexType)}. */
+ private final Map<Outline, DexMethod> generatedOutlines = new HashMap<>();
static final int MAX_IN_SIZE = 5; // Avoid using ranged calls for outlined code.
@@ -652,16 +683,42 @@
// Collect outlining candidates with the methods that can use them.
// TODO(sgjesse): This does not take several usages in the same method into account.
- private class OutlineIdentifier extends OutlineSpotter {
+ private class OutlineMethodIdentifier extends OutlineSpotter {
- OutlineIdentifier(DexEncodedMethod method, BasicBlock block) {
+ private final Map<Outline, List<DexEncodedMethod>> candidateMap;
+
+ OutlineMethodIdentifier(
+ DexEncodedMethod method,
+ BasicBlock block,
+ Map<Outline, List<DexEncodedMethod>> candidateMap) {
+ super(method, block);
+ this.candidateMap = candidateMap;
+ }
+
+ @Override
+ protected void handle(int start, int end, Outline outline) {
+ synchronized (candidateMap) {
+ candidateMap.computeIfAbsent(outline, this::addOutlineMethodList).add(method);
+ }
+ }
+
+ private List<DexEncodedMethod> addOutlineMethodList(Outline outline) {
+ List<DexEncodedMethod> result = new ArrayList<>();
+ candidateMethodLists.add(result);
+ return result;
+ }
+ }
+
+ private class OutlineSiteIdentifier extends OutlineSpotter {
+
+ OutlineSiteIdentifier(DexEncodedMethod method, BasicBlock block) {
super(method, block);
}
@Override
protected void handle(int start, int end, Outline outline) {
- synchronized (candidates) {
- candidates.computeIfAbsent(outline, k -> new ArrayList<>()).add(method);
+ synchronized (outlineSites) {
+ outlineSites.computeIfAbsent(outline, k -> new ArrayList<>()).add(method);
}
}
}
@@ -685,9 +742,9 @@
@Override
protected void handle(int start, int end, Outline outline) {
- if (candidates.containsKey(outline)) {
- DexMethod m = generatedOutlines.get(outline);
- assert m != null;
+ DexMethod m = generatedOutlines.get(outline);
+ if (m != null) {
+ assert removeMethodFromOutlineList(outline);
List<Value> in = new ArrayList<>();
Value returnValue = null;
argumentsMapIndex = 0;
@@ -748,6 +805,14 @@
}
}
}
+
+ /** When assertions are enabled, remove method from the outline's list. */
+ private boolean removeMethodFromOutlineList(Outline outline) {
+ synchronized (outlineSites) {
+ assert outlineSites.get(outline).remove(method);
+ }
+ return true;
+ }
}
public Outliner(AppInfoWithLiveness appInfo, InternalOptions options) {
@@ -756,26 +821,37 @@
this.options = options;
}
- public void identifyCandidates(IRCode code, DexEncodedMethod method) {
+ public BiConsumer<IRCode, DexEncodedMethod> identifyCandidateMethods() {
+ // Since optimizations may change the map identity of Outline objects (e.g. by setting the
+ // out-value of invokes to null), this map must not be used except for identifying methods
+ // potentially relevant to outlining. OutlineMethodIdentifier will add method lists to
+ // candidateMethodLists whenever it adds an entry to candidateMap.
+ Map<Outline, List<DexEncodedMethod>> candidateMap = new HashMap<>();
+ assert candidateMethodLists.isEmpty();
+ return (code, method) -> {
+ assert !(method.getCode() instanceof OutlineCode);
+ for (BasicBlock block : code.blocks) {
+ new OutlineMethodIdentifier(method, block, candidateMap).process();
+ }
+ };
+ }
+
+ public void identifyOutlineSites(IRCode code, DexEncodedMethod method) {
assert !(method.getCode() instanceof OutlineCode);
for (BasicBlock block : code.blocks) {
- new OutlineIdentifier(method, block).process();
+ new OutlineSiteIdentifier(method, block).process();
}
}
public boolean selectMethodsForOutlining() {
assert methodsSelectedForOutlining.size() == 0;
- List<Outline> toRemove = new ArrayList<>();
- for (Entry<Outline, List<DexEncodedMethod>> entry : candidates.entrySet()) {
- if (entry.getValue().size() < options.outline.threshold) {
- toRemove.add(entry.getKey());
- } else {
- methodsSelectedForOutlining.addAll(entry.getValue());
+ assert outlineSites.size() == 0;
+ for (List<DexEncodedMethod> outlineMethods : candidateMethodLists) {
+ if (outlineMethods.size() >= options.outline.threshold) {
+ methodsSelectedForOutlining.addAll(outlineMethods);
}
}
- for (Outline outline : toRemove) {
- candidates.remove(outline);
- }
+ candidateMethodLists.clear();
return methodsSelectedForOutlining.size() > 0;
}
@@ -783,6 +859,79 @@
return methodsSelectedForOutlining;
}
+ public DexProgramClass buildOutlinerClass(DexType type) {
+ // Build the outlined methods.
+ // By now the candidates are the actual selected outlines. Name the generated methods in a
+ // consistent order, to provide deterministic output.
+ List<Outline> outlines = selectOutlines();
+ outlines.sort(Comparator.naturalOrder());
+ DexEncodedMethod[] direct = new DexEncodedMethod[outlines.size()];
+ int count = 0;
+ for (Outline outline : outlines) {
+ MethodAccessFlags methodAccess =
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC, false);
+ DexString methodName = dexItemFactory.createString(OutlineOptions.METHOD_PREFIX + count);
+ DexMethod method = outline.buildMethod(type, methodName);
+ List<DexEncodedMethod> sites = outlineSites.get(outline);
+ assert !sites.isEmpty();
+ direct[count] =
+ new DexEncodedMethod(
+ method,
+ methodAccess,
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ new OutlineCode(outline));
+ if (options.isGeneratingClassFiles()) {
+ direct[count].upgradeClassFileVersion(sites.get(0).getClassFileVersion());
+ }
+ generatedOutlines.put(outline, method);
+ count++;
+ }
+ // No need to sort the direct methods as they are generated in sorted order.
+
+ // Build the outliner class.
+ DexType superType = dexItemFactory.createType("Ljava/lang/Object;");
+ DexTypeList interfaces = DexTypeList.empty();
+ DexString sourceFile = dexItemFactory.createString("outline");
+ ClassAccessFlags accessFlags = ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC);
+ DexProgramClass clazz =
+ new DexProgramClass(
+ type,
+ null,
+ new SynthesizedOrigin("outlining", getClass()),
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ null,
+ Collections.emptyList(),
+ // TODO: Build dex annotations structure.
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY, // Static fields.
+ DexEncodedField.EMPTY_ARRAY, // Instance fields.
+ direct,
+ DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
+ options.itemFactory.getSkipNameValidationForTesting());
+ if (options.isGeneratingClassFiles()) {
+ // All program classes must have a class-file version. Use Java 6.
+ clazz.setClassFileVersion(Opcodes.V1_6);
+ }
+ return clazz;
+ }
+
+ private List<Outline> selectOutlines() {
+ assert outlineSites.size() > 0;
+ assert candidateMethodLists.isEmpty();
+ List<Outline> result = new ArrayList<>();
+ for (Entry<Outline, List<DexEncodedMethod>> entry : outlineSites.entrySet()) {
+ if (entry.getValue().size() >= options.outline.threshold) {
+ result.add(entry.getKey());
+ }
+ }
+ return result;
+ }
+
public void applyOutliningCandidate(IRCode code, DexEncodedMethod method) {
assert !(method.getCode() instanceof OutlineCode);
ListIterator<BasicBlock> blocksIterator = code.blocks.listIterator();
@@ -794,6 +943,13 @@
}
}
+ public boolean checkAllOutlineSitesFoundAgain() {
+ for (Outline outline : generatedOutlines.keySet()) {
+ assert outlineSites.get(outline).isEmpty() : outlineSites.get(outline);
+ }
+ return true;
+ }
+
static public void noProcessing(IRCode code, DexEncodedMethod method) {
// No operation.
}
@@ -1004,9 +1160,8 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod,
- AppInfo appInfo, InternalOptions options, Origin origin)
- throws ApiLevelException {
+ public IRCode buildIR(
+ DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
OutlineSourceCode source = new OutlineSourceCode(outline);
IRBuilder builder = new IRBuilder(encodedMethod, appInfo, source, options);
return builder.build();
@@ -1037,81 +1192,4 @@
return null;
}
}
-
-
- public DexProgramClass buildOutlinerClass(DexType type) {
- if (candidates.size() == 0) {
- return null;
- }
-
- // Build the outlined methods.
- DexEncodedMethod[] direct = new DexEncodedMethod[candidates.size()];
- int count = 0;
-
- // By now the candidates are the actual selected outlines. Name the generated methods in a
- // consistent order, to provide deterministic output.
- List<Outline> outlines = new ArrayList<>(candidates.keySet());
- outlines.sort(Comparator.naturalOrder());
- for (Outline outline : outlines) {
- MethodAccessFlags methodAccess =
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_STATIC, false);
- DexString methodName = dexItemFactory.createString(OutlineOptions.METHOD_PREFIX + count);
- DexMethod method = outline.buildMethod(type, methodName);
- direct[count] = new DexEncodedMethod(method, methodAccess, DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(), new OutlineCode(outline));
- generatedOutlines.put(outline, method);
- count++;
- }
- // No need to sort the direct methods as they are generated in sorted order.
-
- // Build the outliner class.
- DexType superType = dexItemFactory.createType("Ljava/lang/Object;");
- DexTypeList interfaces = DexTypeList.empty();
- DexString sourceFile = dexItemFactory.createString("outline");
- ClassAccessFlags accessFlags = ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC);
- DexProgramClass clazz =
- new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin("outlining", getClass()),
- accessFlags,
- superType,
- interfaces,
- sourceFile,
- null,
- Collections.emptyList(),
- // TODO: Build dex annotations structure.
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY, // Static fields.
- DexEncodedField.EMPTY_ARRAY, // Instance fields.
- direct,
- DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
- options.itemFactory.getSkipNameValidationForTesting());
- if (options.isGeneratingClassFiles()) {
- // Don't set class file version below 50.0 (JDK release 1.6).
- clazz.setClassFileVersion(Math.max(50, getClassFileVersion()));
- }
-
- return clazz;
- }
-
- private int getClassFileVersion() {
- assert options.isGeneratingClassFiles();
- int classFileVersion = -1;
- Set<DexType> seen = Sets.newIdentityHashSet();
- for (List<DexEncodedMethod> methods : candidates.values()) {
- for (DexEncodedMethod method : methods) {
- DexType holder = method.method.holder;
- if (seen.add(holder)) {
- DexProgramClass programClass = appInfo.definitionFor(holder).asProgramClass();
- assert programClass != null : "Attempt to outline from library class";
- assert programClass.originatesFromClassResource()
- : "Attempt to outline from non-classfile input to classfile output";
- classFileVersion = Math.max(classFileVersion, programClass.getClassFileVersion());
- }
- }
- }
- return classFileVersion;
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
index 1284671..a586355 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
@@ -75,7 +74,7 @@
intArrayType = appInfo.dexItemFactory.createType("[I");
}
- public AppInfoWithLiveness run() throws ApiLevelException {
+ public AppInfoWithLiveness run() {
for (DexProgramClass clazz : appInfo.classes()) {
processClasses(clazz);
}
@@ -85,7 +84,7 @@
return appInfo;
}
- private void processClasses(DexProgramClass clazz) throws ApiLevelException {
+ private void processClasses(DexProgramClass clazz) {
// Switchmap classes are synthetic and have a class initializer.
if (!clazz.accessFlags.isSynthetic() && !clazz.hasClassInitializer()) {
return;
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 7d13b1a..9ff44eb 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
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.optimize.classinliner;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
@@ -40,7 +39,7 @@
private static final Map<DexField, Integer> NO_MAPPING = new IdentityHashMap<>();
public interface InlinerAction {
- void inline(Map<InvokeMethodWithReceiver, InliningInfo> methods) throws ApiLevelException;
+ void inline(Map<InvokeMethodWithReceiver, InliningInfo> methods);
}
public ClassInliner(DexItemFactory factory) {
@@ -110,7 +109,7 @@
DexEncodedMethod method,
IRCode code,
Predicate<DexEncodedMethod> isProcessedConcurrently,
- InlinerAction inliner) throws ApiLevelException {
+ InlinerAction inliner) {
// Collect all the new-instance instructions in the code before inlining.
List<NewInstance> newInstances = Streams.stream(code.instructionIterator())
@@ -246,8 +245,8 @@
}
}
- private void inlineAllCalls(InlinerAction inliner,
- Map<InvokeMethodWithReceiver, InliningInfo> methodCalls) throws ApiLevelException {
+ private void inlineAllCalls(
+ InlinerAction inliner, Map<InvokeMethodWithReceiver, InliningInfo> methodCalls) {
if (!methodCalls.isEmpty()) {
inliner.inline(methodCalls);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 466117f..d1b56f2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.optimize.lambda;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
@@ -187,9 +186,13 @@
}
}
- public final void applyLambdaClassMapping(DexApplication app,
- IRConverter converter, OptimizationFeedback feedback, Builder<?> builder,
- ExecutorService executorService) throws ExecutionException, ApiLevelException {
+ public final void applyLambdaClassMapping(
+ DexApplication app,
+ IRConverter converter,
+ OptimizationFeedback feedback,
+ Builder<?> builder,
+ ExecutorService executorService)
+ throws ExecutionException {
if (lambdas.isEmpty()) {
return;
}
@@ -294,8 +297,7 @@
}
}
- private void rewriteLambdaReferences(
- IRConverter converter, OptimizationFeedback feedback) throws ApiLevelException {
+ private void rewriteLambdaReferences(IRConverter converter, OptimizationFeedback feedback) {
List<DexEncodedMethod> methods =
methodsToReprocess
.stream()
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 2f055ce..df30c18 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -636,13 +636,21 @@
LiveIntervals intervals = current.getLiveIntervals();
assert intervals.getRegisterLimit() == Constants.U16BIT_MAX;
boolean canUseArgumentRegister = true;
+ boolean couldUseArgumentRegister = true;
for (LiveIntervals child : intervals.getSplitChildren()) {
- if (child.getRegisterLimit() < highestUsedRegister()) {
- canUseArgumentRegister = false;
- break;
+ int registerConstraint = child.getRegisterLimit();
+ if (registerConstraint < Constants.U16BIT_MAX) {
+ couldUseArgumentRegister = false;
+
+ if (registerConstraint < highestUsedRegister()) {
+ canUseArgumentRegister = false;
+ break;
+ }
}
}
- if (canUseArgumentRegister) {
+ if (canUseArgumentRegister && !couldUseArgumentRegister) {
+ // Only return true if there is a constrained use where it turns out that we can use the
+ // original argument register. This way we will not unnecessarily redo move insertion.
argumentRegisterUnsplit = true;
for (LiveIntervals child : intervals.getSplitChildren()) {
child.clearRegisterAssignment();
@@ -805,8 +813,8 @@
if (overlappingMoveExceptionIntervals) {
for (LiveIntervals intervals : moveExceptionIntervals) {
if (intervals.getUses().size() > 1) {
- LiveIntervalsUse secondUse = intervals.getUses().stream().skip(1).findFirst().get();
- LiveIntervals split = intervals.splitBefore(secondUse.getPosition());
+ LiveIntervals split =
+ intervals.splitBefore(intervals.getFirstUse() + INSTRUCTION_NUMBER_DELTA);
unhandled.add(split);
}
}
@@ -1346,6 +1354,12 @@
if (!hasDedicatedMoveExceptionRegister()) {
return false;
}
+ // If there are that many move exception intervals we don't spent the time
+ // going through them all. In that case it is unlikely that we can reuse the move exception
+ // register in any case.
+ if (moveExceptionIntervals.size() > 1000) {
+ return true;
+ }
for (LiveIntervals moveExceptionInterval : moveExceptionIntervals) {
if (intervals.anySplitOverlaps(moveExceptionInterval)) {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index 9259485..0ba49d3 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -21,15 +21,27 @@
private final DexType targetReceiver;
private final DexMethod target;
private final Invoke.Type invokeType;
+ private final boolean castResult;
public ForwardMethodSourceCode(DexType receiver, DexProto proto,
DexType targetReceiver, DexMethod target, Invoke.Type invokeType) {
+ this(receiver, proto, targetReceiver, target, invokeType, false);
+ }
+
+ public ForwardMethodSourceCode(
+ DexType receiver,
+ DexProto proto,
+ DexType targetReceiver,
+ DexMethod target,
+ Invoke.Type invokeType,
+ boolean castResult) {
super(receiver, proto);
assert (targetReceiver == null) == (invokeType == Invoke.Type.STATIC);
this.target = target;
this.targetReceiver = targetReceiver;
this.invokeType = invokeType;
+ this.castResult = castResult;
assert checkSignatures();
switch (invokeType) {
@@ -67,7 +79,7 @@
assert (source.isClassType() && target.isClassType()) || source == target;
}
- assert this.proto.returnType == target.proto.returnType;
+ assert this.proto.returnType == target.proto.returnType || castResult;
return true;
}
@@ -99,6 +111,9 @@
ValueType valueType = ValueType.fromDexType(proto.returnType);
int tempValue = nextRegister(valueType);
add(builder -> builder.addMoveResult(tempValue));
+ if (this.proto.returnType != target.proto.returnType) {
+ add(builder -> builder.addCheckCast(tempValue, this.proto.returnType));
+ }
add(builder -> builder.addReturn(valueType, tempValue));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
index f8134f4..a5807c3 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.synthetic;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.Code;
@@ -40,9 +39,7 @@
@Override
public final IRCode buildIR(
- DexEncodedMethod encodedMethod, AppInfo appInfo,
- InternalOptions options, Origin origin)
- throws ApiLevelException {
+ DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
return new IRBuilder(encodedMethod, appInfo, sourceCode, options).build();
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
index 03206b5..80a439a 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo.NO_THROW;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexProto;
@@ -18,9 +17,9 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.utils.ThrowingConsumer;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Predicate;
public abstract class SyntheticSourceCode implements SourceCode {
@@ -43,7 +42,7 @@
private Value[] paramValues;
// Instruction constructors
- private List<ThrowingConsumer<IRBuilder, ApiLevelException>> constructors = new ArrayList<>();
+ private List<Consumer<IRBuilder>> constructors = new ArrayList<>();
private List<Predicate<IRBuilder>> traceEvents = new ArrayList<>();
protected SyntheticSourceCode(DexType receiver, DexProto proto) {
@@ -63,12 +62,11 @@
}
}
- protected final void add(ThrowingConsumer<IRBuilder, ApiLevelException> constructor) {
+ protected final void add(Consumer<IRBuilder> constructor) {
add(constructor, doesNotEndBlock);
}
- protected final void add(
- ThrowingConsumer<IRBuilder, ApiLevelException> constructor, Predicate<IRBuilder> traceEvent) {
+ protected final void add(Consumer<IRBuilder> constructor, Predicate<IRBuilder> traceEvent) {
constructors.add(constructor);
traceEvents.add(traceEvent);
}
@@ -189,8 +187,7 @@
@Override
public final void buildInstruction(
- IRBuilder builder, int instructionIndex, boolean firstBlockInstruction)
- throws ApiLevelException {
+ IRBuilder builder, int instructionIndex, boolean firstBlockInstruction) {
constructors.get(instructionIndex).accept(builder);
}
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 2970fb4..7a25e1a 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -108,7 +108,7 @@
private void writeClass(DexProgramClass clazz, ClassFileConsumer consumer) throws IOException {
ClassWriter writer = new ClassWriter(0);
writer.visitSource(clazz.sourceFile != null ? clazz.sourceFile.toString() : null, null);
- int version = clazz.getClassFileVersion();
+ int version = getClassFileVersion(clazz);
int access = clazz.accessFlags.getAsCfAccessFlags();
String desc = namingLens.lookupDescriptor(clazz.type).toString();
String name = namingLens.lookupInternalName(clazz.type);
@@ -161,6 +161,17 @@
options.reporter, handler -> consumer.accept(result, desc, handler));
}
+ private int getClassFileVersion(DexProgramClass clazz) {
+ int version = clazz.getClassFileVersion();
+ for (DexEncodedMethod method : clazz.directMethods()) {
+ version = Math.max(version, method.getClassFileVersion());
+ }
+ for (DexEncodedMethod method : clazz.virtualMethods()) {
+ version = Math.max(version, method.getClassFileVersion());
+ }
+ return version;
+ }
+
private DexValue getSystemAnnotationValue(DexAnnotationSet annotations, DexType type) {
DexAnnotation annotation = annotations.getFirstMatching(type);
if (annotation == null) {
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 4f49fbe..56e381b 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -34,6 +34,7 @@
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
class ClassNameMinifier {
@@ -50,6 +51,7 @@
private final ImmutableList<String> packageDictionary;
private final ImmutableList<String> classDictionary;
private final boolean keepInnerClassStructure;
+ private final Set<DexType> keepPackageName;
private final Namespace topLevelState;
@@ -69,6 +71,12 @@
this.packageDictionary = options.proguardConfiguration.getPackageObfuscationDictionary();
this.classDictionary = options.proguardConfiguration.getClassObfuscationDictionary();
this.keepInnerClassStructure = options.proguardConfiguration.getKeepAttributes().signature;
+ this.keepPackageName =
+ rootSet.keepPackageName.stream()
+ .filter(DexClass.class::isInstance)
+ .map(DexClass.class::cast)
+ .map(DexClass::getType)
+ .collect(Collectors.toSet());
// Initialize top-level naming state.
topLevelState = new Namespace(
@@ -92,7 +100,7 @@
timing.begin("rename-classes");
for (DexClass clazz : classes) {
if (!renaming.containsKey(clazz.type)) {
- DexString renamed = computeName(clazz);
+ DexString renamed = computeName(clazz.type);
renaming.put(clazz.type, renamed);
}
}
@@ -231,27 +239,27 @@
return null;
}
- private DexString computeName(DexClass clazz) {
+ private DexString computeName(DexType type) {
Namespace state = null;
if (keepInnerClassStructure) {
// When keeping the nesting structure of inner classes, we have to insert the name
// of the outer class for the $ prefix.
- DexType outerClass = getOutClassForType(clazz.type);
+ DexType outerClass = getOutClassForType(type);
if (outerClass != null) {
state = getStateForOuterClass(outerClass);
}
}
if (state == null) {
- state = getStateForClass(clazz);
+ state = getStateForClass(type);
}
return state.nextTypeName();
}
- private Namespace getStateForClass(DexClass clazz) {
- String packageName = getPackageBinaryNameFromJavaType(clazz.type.getPackageDescriptor());
+ private Namespace getStateForClass(DexType type) {
+ String packageName = getPackageBinaryNameFromJavaType(type.getPackageDescriptor());
// Check whether the given class should be kept.
// or check whether the given class belongs to a package that is kept for another class.
- if (rootSet.keepPackageName.contains(clazz)
+ if (keepPackageName.contains(type)
|| noObfuscationPrefixes.contains(packageName)) {
return states.computeIfAbsent(packageName, Namespace::new);
}
@@ -307,13 +315,12 @@
DexString renamed = renaming.get(outer);
if (renamed == null) {
// The outer class has not been renamed yet, so rename the outer class first.
- DexClass outerClass = appInfo.definitionFor(outer);
- if (outerClass == null) {
- renamed = outer.descriptor;
- } else {
- renamed = computeName(outerClass);
- renaming.put(outer, renamed);
- }
+ // Note that here we proceed unconditionally---w/o regards to the existence of the outer
+ // class: it could be the case that the outer class is not renamed because it's shrunk.
+ // Even though that's the case, we can _implicitly_ assign a new name to the outer class
+ // and then use that renamed name as a base prefix for the current inner class.
+ renamed = computeName(outer);
+ renaming.put(outer, renamed);
}
String binaryName = getClassBinaryNameFromDescriptor(renamed.toString());
state = new Namespace(binaryName, "$");
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index 2c85270..c766c37 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -299,5 +299,16 @@
}
writer.append(')');
}
+
+ public String toDescriptor() {
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
+ for (String parameterType : parameters) {
+ sb.append(javaTypeToDescriptor(parameterType));
+ }
+ sb.append(')');
+ sb.append(javaTypeToDescriptor(type));
+ return sb.toString();
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureParser.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureParser.java
index 9a5baaf..0cc0d53 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureParser.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureParser.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.naming.signature;
import java.lang.reflect.GenericSignatureFormatError;
+import java.nio.CharBuffer;
/**
* Implements a parser for the generics signature attribute as defined by JVMS 7 $ 4.3.4.
@@ -177,7 +178,7 @@
updateTypeVariableSignature();
break;
default:
- throw new GenericSignatureFormatError();
+ parseError();
}
}
@@ -340,7 +341,7 @@
eof = true;
}
} else {
- throw new GenericSignatureFormatError();
+ parseError("Unexpected end of signature");
}
}
@@ -348,7 +349,7 @@
if (symbol == c) {
scanSymbol();
} else {
- throw new GenericSignatureFormatError();
+ parseError("Expected " + c);
}
}
@@ -395,10 +396,20 @@
// Ident starts with incorrect char.
symbol = 0;
eof = true;
- throw new GenericSignatureFormatError();
+ parseError();
}
} else {
- throw new GenericSignatureFormatError();
+ parseError("Unexpected end of signature");
}
}
+
+ private void parseError() {
+ parseError("Unexpected");
+ }
+
+ private void parseError(String message) {
+ String arrow = CharBuffer.allocate(pos).toString().replace('\0', ' ') + '^';
+ throw new GenericSignatureFormatError(
+ message + " at position " + (pos + 1) + "\n" + String.valueOf(buffer) + "\n" + arrow);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/position/TextRange.java b/src/main/java/com/android/tools/r8/position/TextRange.java
index d7c0f43..5f35aad 100644
--- a/src/main/java/com/android/tools/r8/position/TextRange.java
+++ b/src/main/java/com/android/tools/r8/position/TextRange.java
@@ -45,6 +45,11 @@
}
@Override
+ public String toString() {
+ return "Text range from: '" + getStart() + "', to: '" + getEnd() + "'";
+ }
+
+ @Override
public String getDescription() {
return start.getDescription();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
index e4e2ed7..610bfd3 100644
--- a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
@@ -52,7 +52,7 @@
List<DexEncodedMethod> methods = null;
for (int i = 0; i < virtualMethods.length; i++) {
DexEncodedMethod method = virtualMethods[i];
- if (scope.addMethod(method.method) || !method.accessFlags.isAbstract()) {
+ if (scope.addMethodIfMoreVisible(method) || !method.accessFlags.isAbstract()) {
if (methods != null) {
methods.add(method);
}
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 7e483a7..085d9b3 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.naming.IdentifierNameStringUtils.isReflectionMethod;
import static com.android.tools.r8.shaking.ProguardConfigurationUtils.buildIdentifierNameStringRule;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unreachable;
@@ -461,10 +460,11 @@
DexType baseType = type.toBaseType(appInfo.dexItemFactory);
if (baseType.isClassType()) {
DexClass baseClass = appInfo.definitionFor(baseType);
- if (baseClass != null && !baseClass.isLibraryClass()) {
+ if (baseClass != null && baseClass.isProgramClass()
+ && baseClass.hasDefaultInitializer()) {
markClassAsInstantiatedWithCompatRule(baseClass);
} else {
- // This handles reporting of missing classes.
+ // This also handles reporting of missing classes.
markTypeAsLive(baseType);
}
return true;
@@ -740,7 +740,6 @@
transitionNonAbstractMethodsToLiveAndShadow(
reachableMethods.getItems(), instantiatedType, seen.newNestedScope());
}
- seen = seen.newNestedScope();
for (DexType subInterface : clazz.interfaces.values) {
transitionDefaultMethodsForInstantiatedClass(subInterface, instantiatedType, seen);
}
@@ -749,7 +748,7 @@
private void transitionNonAbstractMethodsToLiveAndShadow(Iterable<DexEncodedMethod> reachable,
DexType instantiatedType, ScopedDexMethodSet seen) {
for (DexEncodedMethod encodedMethod : reachable) {
- if (seen.addMethod(encodedMethod.method)) {
+ if (seen.addMethod(encodedMethod)) {
// Abstract methods do shadow implementations but they cannot be live, as they have no
// code.
if (!encodedMethod.accessFlags.isAbstract()) {
@@ -1349,13 +1348,8 @@
}
private void handleProguardReflectiveBehavior(DexEncodedMethod method) {
- try {
- IRCode code = method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
- code.instructionIterator().forEachRemaining(this::handleProguardReflectiveBehavior);
- } catch (ApiLevelException e) {
- // Ignore this exception here. It will be hit again further in the pipeline when
- // generating code.
- }
+ IRCode code = method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
+ code.instructionIterator().forEachRemaining(this::handleProguardReflectiveBehavior);
}
private void handleProguardReflectiveBehavior(Instruction instruction) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index dd82dfd..d4d4bcb 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -305,8 +305,8 @@
// disableOptimization();
}
- if ((keepAttributePatterns.isEmpty()
- && (rulesWasEmpty || (forceProguardCompatibility && !isObfuscating())))
+ if ((keepAttributePatterns.isEmpty() && rulesWasEmpty)
+ || (forceProguardCompatibility && !isObfuscating())
|| !isShrinking()) {
keepAttributePatterns.addAll(ProguardKeepAttributes.KEEP_ALL);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 4a25e42..ed9cbdb 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -47,6 +47,7 @@
private final DexItemFactory dexItemFactory;
private final Reporter reporter;
+ private final boolean failOnPartiallyImplementedOptions;
private static final List<String> IGNORED_SINGLE_ARG_OPTIONS = ImmutableList.of(
"protomapping",
@@ -96,10 +97,16 @@
public ProguardConfigurationParser(
DexItemFactory dexItemFactory, Reporter reporter) {
+ this(dexItemFactory, reporter, true);
+ }
+
+ public ProguardConfigurationParser(
+ DexItemFactory dexItemFactory, Reporter reporter, boolean failOnPartiallyImplementedOptions) {
this.dexItemFactory = dexItemFactory;
configurationBuilder = ProguardConfiguration.builder(dexItemFactory, reporter);
this.reporter = reporter;
+ this.failOnPartiallyImplementedOptions = failOnPartiallyImplementedOptions;
}
public ProguardConfiguration.Builder getConfigurationBuilder() {
@@ -219,6 +226,10 @@
ProguardCheckDiscardRule rule = parseCheckDiscardRule();
configurationBuilder.addRule(rule);
} else if (acceptString("keepdirectories")) {
+ // TODO(74279367): Report an error until it's fully supported.
+ if (failOnPartiallyImplementedOptions) {
+ failPartiallyImplementedOption("-keepdirectories", optionStart);
+ }
parsePathFilter(configurationBuilder::addKeepDirectories);
} else if (acceptString("keep")) {
ProguardKeepRule rule = parseKeepRule();
@@ -339,11 +350,17 @@
} else if (acceptString("adaptclassstrings")) {
parseClassFilter(configurationBuilder::addAdaptClassStringsPattern);
} else if (acceptString("adaptresourcefilenames")) {
- // TODO(b/76377381): should be report an error until it's fully supported.
+ // TODO(76377381): Report an error until it's fully supported.
+ if (failOnPartiallyImplementedOptions) {
+ failPartiallyImplementedOption("-adaptresourcefilenames", optionStart);
+ }
parsePathFilter(configurationBuilder::addAdaptResourceFilenames);
} else if (acceptString("adaptresourcefilecontents")) {
+ // TODO(36847655): Report an error until it's fully supported.
+ if (failOnPartiallyImplementedOptions) {
+ failPartiallyImplementedOption("-adaptresourcefilecontents", optionStart);
+ }
parsePathFilter(configurationBuilder::addAdaptResourceFilecontents);
- // TODO(b/37139570): should be report an error until it's fully supported.
} else if (acceptString("identifiernamestring")) {
configurationBuilder.addRule(parseIdentifierNameStringRule());
} else if (acceptString("if")) {
@@ -1473,6 +1490,11 @@
"Option -" + optionName + " overrides -" + victim, origin, getPosition(start)));
}
+ private void failPartiallyImplementedOption(String optionName, TextPosition start) {
+ throw reporter.fatalError(new StringDiagnostic(
+ "Option " + optionName + " currently not supported", origin, getPosition(start)));
+ }
+
private Position getPosition(TextPosition start) {
if (start.getOffset() == position) {
return start;
diff --git a/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java b/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java
index 39f07ee..3587cf4 100644
--- a/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java
+++ b/src/main/java/com/android/tools/r8/shaking/ScopedDexMethodSet.java
@@ -3,19 +3,20 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.HashMap;
+import java.util.Map;
class ScopedDexMethodSet {
private static final Equivalence<DexMethod> METHOD_EQUIVALENCE = MethodSignatureEquivalence.get();
private final ScopedDexMethodSet parent;
- private final Set<Wrapper<DexMethod>> items = new HashSet<>();
+ private final Map<Wrapper<DexMethod>, DexEncodedMethod> items = new HashMap<>();
public ScopedDexMethodSet() {
this(null);
@@ -29,14 +30,32 @@
return new ScopedDexMethodSet(this);
}
- private boolean contains(Wrapper<DexMethod> item) {
- return items.contains(item)
- || ((parent != null) && parent.contains(item));
+ private DexEncodedMethod lookup(Wrapper<DexMethod> item) {
+ DexEncodedMethod ownMethod = items.get(item);
+ return ownMethod != null ? ownMethod : (parent != null ? parent.lookup(item) : null);
}
- public boolean addMethod(DexMethod method) {
- Wrapper<DexMethod> wrapped = METHOD_EQUIVALENCE.wrap(method);
- return !contains(wrapped) && items.add(wrapped);
+ private boolean contains(Wrapper<DexMethod> item) {
+ return lookup(item) != null;
+ }
+
+ public boolean addMethod(DexEncodedMethod method) {
+ Wrapper<DexMethod> wrapped = METHOD_EQUIVALENCE.wrap(method.method);
+ if (contains(wrapped)) {
+ return false;
+ }
+ items.put(wrapped, method);
+ return true;
+ }
+
+ public boolean addMethodIfMoreVisible(DexEncodedMethod method) {
+ Wrapper<DexMethod> wrapped = METHOD_EQUIVALENCE.wrap(method.method);
+ DexEncodedMethod existing = lookup(wrapped);
+ if (existing == null || method.accessFlags.isMoreVisibleThan(existing.accessFlags)) {
+ items.put(wrapped, method);
+ return true;
+ }
+ return false;
}
public ScopedDexMethodSet getParent() {
diff --git a/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java b/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
index cd21d17..1a64ab0 100644
--- a/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
@@ -35,34 +35,40 @@
@Override
public synchronized void open() {
assert !closed;
- openCount ++;
+ openCount++;
}
@Override
- public synchronized void close() throws IOException {
+ public synchronized void close(DiagnosticsHandler handler) {
assert !closed;
openCount--;
if (openCount == 0) {
closed = true;
- if (stream != null) {
- stream.close();
+ try {
+ getStreamRaw().close();
stream = null;
+ } catch (IOException e) {
+ handler.error(new ExceptionDiagnostic(e, origin));
}
}
}
+ private ZipOutputStream getStreamRaw() throws IOException {
+ if (stream != null) {
+ return stream;
+ }
+ stream = new ZipOutputStream(Files.newOutputStream(
+ archive, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING));
+ return stream;
+ }
+
/** Get or open the zip output stream. */
private synchronized ZipOutputStream getStream(DiagnosticsHandler handler) {
assert !closed;
- if (stream == null) {
- try {
- stream =
- new ZipOutputStream(
- Files.newOutputStream(
- archive, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING));
- } catch (IOException e) {
- handler.error(new ExceptionDiagnostic(e, origin));
- }
+ try {
+ getStreamRaw();
+ } catch (IOException e) {
+ handler.error(new ExceptionDiagnostic(e, origin));
}
return stream;
}
diff --git a/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java b/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java
index 2dc4a2d..2058d39 100644
--- a/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/DirectoryBuilder.java
@@ -30,7 +30,7 @@
}
@Override
- public void close() {
+ public void close(DiagnosticsHandler handler) {
}
@Override
diff --git a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
index 9c7f525..fe8adfa 100644
--- a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.ResourceException;
@@ -15,7 +14,6 @@
import java.nio.file.FileSystemException;
import java.nio.file.Paths;
import java.util.function.Consumer;
-import java.util.function.Function;
public abstract class ExceptionUtils {
@@ -37,31 +35,26 @@
}
public interface CompileAction {
- void run() throws IOException, CompilationException, CompilationError, ResourceException;
+ void run() throws IOException, CompilationError, ResourceException;
}
public static void withD8CompilationHandler(Reporter reporter, CompileAction action)
throws CompilationFailedException {
- withCompilationHandler(reporter, action, CompilationException::getMessageForD8);
+ withCompilationHandler(reporter, action);
}
public static void withR8CompilationHandler(Reporter reporter, CompileAction action)
throws CompilationFailedException {
- withCompilationHandler(reporter, action, CompilationException::getMessageForR8);
+ withCompilationHandler(reporter, action);
}
- public static void withCompilationHandler(
- Reporter reporter,
- CompileAction action,
- Function<CompilationException, String> compilerMessage)
+ public static void withCompilationHandler(Reporter reporter, CompileAction action)
throws CompilationFailedException {
try {
try {
action.run();
} catch (IOException e) {
throw reporter.fatalError(new ExceptionDiagnostic(e, extractIOExceptionOrigin(e)));
- } catch (CompilationException e) {
- throw reporter.fatalError(new StringDiagnostic(compilerMessage.apply(e)), e);
} catch (CompilationError e) {
throw reporter.fatalError(e);
} catch (ResourceException e) {
diff --git a/src/main/java/com/android/tools/r8/utils/FlagFile.java b/src/main/java/com/android/tools/r8/utils/FlagFile.java
new file mode 100644
index 0000000..4791217
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/FlagFile.java
@@ -0,0 +1,48 @@
+// 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.origin.Origin;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FlagFile {
+
+ private static class FlagFileOrigin extends Origin {
+ private final Path path;
+
+ protected FlagFileOrigin(Path path) {
+ super(Origin.root());
+ this.path = path;
+ }
+
+ @Override
+ public String part() {
+ return "flag file argument: '@" + path + "'";
+ }
+ }
+
+ public static String[] expandFlagFiles(String[] args, Reporter reporter) {
+ List<String> flags = new ArrayList<>(args.length);
+ for (String arg : args) {
+ if (arg.startsWith("@")) {
+ Path flagFilePath = Paths.get(arg.substring(1));
+ try {
+ flags.addAll(Files.readAllLines(flagFilePath));
+ } catch (IOException e) {
+ Origin origin = new FlagFileOrigin(flagFilePath);
+ reporter.error(new ExceptionDiagnostic(e, origin));
+ }
+ } else {
+ flags.add(arg);
+ }
+ }
+ return flags.toArray(new String[flags.size()]);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/OutputBuilder.java b/src/main/java/com/android/tools/r8/utils/OutputBuilder.java
index 27d07c4..9237485 100644
--- a/src/main/java/com/android/tools/r8/utils/OutputBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/OutputBuilder.java
@@ -7,14 +7,15 @@
import com.android.tools.r8.DataEntryResource;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.origin.Origin;
-import java.io.Closeable;
import java.nio.file.Path;
-public interface OutputBuilder extends Closeable {
+public interface OutputBuilder {
char NAME_SEPARATOR = '/';
void open();
+ void close(DiagnosticsHandler handler);
+
void addDirectory(String name, DiagnosticsHandler handler);
void addFile(String name, DataEntryResource content, DiagnosticsHandler handler);
diff --git a/src/main/java/com/android/tools/r8/utils/Reporter.java b/src/main/java/com/android/tools/r8/utils/Reporter.java
index ebb7ce6..b09f164 100644
--- a/src/main/java/com/android/tools/r8/utils/Reporter.java
+++ b/src/main/java/com/android/tools/r8/utils/Reporter.java
@@ -3,10 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
+import com.android.tools.r8.BaseCompilerCommand;
import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.D8Command;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.R8Command;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.MainDexOverflow;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
@@ -16,12 +20,18 @@
public class Reporter implements DiagnosticsHandler {
private final DiagnosticsHandler clientHandler;
+ private final BaseCompilerCommand command;
private int errorCount = 0;
private Diagnostic lastError;
private final Collection<Throwable> suppressedExceptions = new ArrayList<>();
public Reporter(DiagnosticsHandler clientHandler) {
+ this(clientHandler, null);
+ }
+
+ public Reporter(DiagnosticsHandler clientHandler, BaseCompilerCommand command) {
this.clientHandler = clientHandler;
+ this.command = command;
}
@Override
@@ -75,6 +85,19 @@
}
/**
+ * @throws AbortException always.
+ */
+ public RuntimeException fatalError(MainDexOverflow e) {
+ if (command instanceof R8Command) {
+ return fatalError(new StringDiagnostic(e.getMessageForR8()));
+ } else if (command instanceof D8Command) {
+ return fatalError(new StringDiagnostic(e.getMessageForD8()));
+ } else {
+ return fatalError(new StringDiagnostic(e.getMessage()));
+ }
+ }
+
+ /**
* @throws AbortException if any error was reported.
*/
public void failIfPendingErrors() {
diff --git a/src/test/examples/abstractmethodremoval/AbstractMethodRemoval.java b/src/test/examples/abstractmethodremoval/AbstractMethodRemoval.java
new file mode 100644
index 0000000..1da772d
--- /dev/null
+++ b/src/test/examples/abstractmethodremoval/AbstractMethodRemoval.java
@@ -0,0 +1,34 @@
+// 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 abstractmethodremoval;
+
+import abstractmethodremoval.a.PackageBase;
+import abstractmethodremoval.a.Public;
+import abstractmethodremoval.b.Impl1;
+import abstractmethodremoval.b.Impl2;
+
+public class AbstractMethodRemoval {
+
+ private static int dummy;
+
+ public static void main(String[] args) {
+ dummy = args.length;
+ invokeFoo(new Impl1());
+ invokeFoo(new Impl2());
+ invokeFoo(new Impl2());
+ PackageBase.invokeFoo(new Impl1());
+ PackageBase.invokeFoo(new Impl2());
+ PackageBase.invokeFoo(new Impl2());
+ }
+
+ private static void invokeFoo(Public aPublic) {
+ // Enough instructions to avoid inlining.
+ aPublic.foo(dummy() + dummy() + dummy() + dummy() + dummy() + dummy() + dummy() + dummy());
+ }
+
+ private static int dummy() {
+ // Enough instructions to avoid inlining.
+ return dummy + dummy + dummy + dummy + dummy + dummy + dummy + dummy + dummy + dummy + dummy;
+ }
+}
diff --git a/src/test/examples/abstractmethodremoval/a/PackageBase.java b/src/test/examples/abstractmethodremoval/a/PackageBase.java
new file mode 100644
index 0000000..1075b57
--- /dev/null
+++ b/src/test/examples/abstractmethodremoval/a/PackageBase.java
@@ -0,0 +1,12 @@
+// 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 abstractmethodremoval.a;
+
+public abstract class PackageBase {
+ abstract void foo(int i);
+
+ public static void invokeFoo(PackageBase o) {
+ o.foo(0);
+ }
+}
diff --git a/src/test/examples/abstractmethodremoval/a/Public.java b/src/test/examples/abstractmethodremoval/a/Public.java
new file mode 100644
index 0000000..492ab87
--- /dev/null
+++ b/src/test/examples/abstractmethodremoval/a/Public.java
@@ -0,0 +1,9 @@
+// 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 abstractmethodremoval.a;
+
+public abstract class Public extends PackageBase {
+ @Override
+ public abstract void foo(int i);
+}
diff --git a/src/test/examples/abstractmethodremoval/b/Impl1.java b/src/test/examples/abstractmethodremoval/b/Impl1.java
new file mode 100644
index 0000000..bfdf4d1
--- /dev/null
+++ b/src/test/examples/abstractmethodremoval/b/Impl1.java
@@ -0,0 +1,13 @@
+// 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 abstractmethodremoval.b;
+
+import abstractmethodremoval.a.Public;
+
+public class Impl1 extends Public {
+ @Override
+ public void foo(int i) {
+ System.out.println("Impl1.foo(" + i + ")");
+ }
+}
diff --git a/src/test/examples/abstractmethodremoval/b/Impl2.java b/src/test/examples/abstractmethodremoval/b/Impl2.java
new file mode 100644
index 0000000..a92e2a1
--- /dev/null
+++ b/src/test/examples/abstractmethodremoval/b/Impl2.java
@@ -0,0 +1,13 @@
+// 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 abstractmethodremoval.b;
+
+import abstractmethodremoval.a.Public;
+
+public class Impl2 extends Public {
+ @Override
+ public void foo(int i) {
+ System.out.println("Impl2.foo(" + i + ")");
+ }
+}
diff --git a/src/test/examples/abstractmethodremoval/keep-rules.txt b/src/test/examples/abstractmethodremoval/keep-rules.txt
new file mode 100644
index 0000000..ec37858
--- /dev/null
+++ b/src/test/examples/abstractmethodremoval/keep-rules.txt
@@ -0,0 +1 @@
+-keep public class abstractmethodremoval.AbstractMethodRemoval { public static void main(...); }
diff --git a/src/test/examples/catchhandleroverlap/CatchHandlerOverlap.java b/src/test/examples/catchhandleroverlap/CatchHandlerOverlap.java
new file mode 100644
index 0000000..7a4950c
--- /dev/null
+++ b/src/test/examples/catchhandleroverlap/CatchHandlerOverlap.java
@@ -0,0 +1,33 @@
+// 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 catchhandleroverlap;
+
+public class CatchHandlerOverlap {
+ private static void f() throws Exception {
+ throw new Exception("f");
+ }
+
+ private static void g() throws Exception {
+ throw new Exception("g");
+ }
+
+ private static void h(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9,
+ int i10, int i11, int i12, int i13, int i14, int i15, int i16, int i17) {
+ System.out.println(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 +
+ i12 + i13 + i14 + i15 + i16 + i17);
+ try {
+ f();
+ } catch (Exception e0) {
+ try {
+ g();
+ } catch (Exception e1) {
+ System.out.println(e0.getMessage() + " " + e1.getMessage());
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ h(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/AsmTestBase.java b/src/test/java/com/android/tools/r8/AsmTestBase.java
index db26fe6..9cc2b48 100644
--- a/src/test/java/com/android/tools/r8/AsmTestBase.java
+++ b/src/test/java/com/android/tools/r8/AsmTestBase.java
@@ -54,8 +54,8 @@
}
private void ensureSameOutput(String main, AndroidApp app, byte[]... classes)
- throws IOException, CompilationException, ExecutionException, CompilationFailedException,
- ProguardRuleParserException {
+ throws IOException, ExecutionException, CompilationFailedException,
+ ProguardRuleParserException {
ProcessResult javaResult = runOnJava(main, classes);
ProcessResult d8Result = runOnArtRaw(compileWithD8(app), main);
ProcessResult r8Result = runOnArtRaw(compileWithR8(app), main);
@@ -88,8 +88,8 @@
}
protected void ensureSameOutputAfterMerging(String main, byte[]... classes)
- throws IOException, CompilationException, ExecutionException,
- CompilationFailedException, ProguardRuleParserException {
+ throws IOException, ExecutionException, CompilationFailedException,
+ ProguardRuleParserException {
AndroidApp app = buildAndroidApp(classes);
// Compile to dex files with D8.
AndroidApp dexApp = compileWithD8(app);
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index dc16cac..1b846a5 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -6,12 +6,16 @@
import static com.android.tools.r8.R8CommandTest.getOutputPath;
import static com.android.tools.r8.ToolHelper.EXAMPLES_BUILD_DIR;
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+import static java.nio.file.StandardOpenOption.CREATE_NEW;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import com.android.sdklib.AndroidVersion;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
@@ -20,6 +24,7 @@
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
@@ -87,6 +92,39 @@
}
@Test
+ public void flagsFile() throws Throwable {
+ Path working = temp.getRoot().toPath();
+ Path flagsFile = working.resolve("flags.txt");
+ Path input = Paths.get(EXAMPLES_BUILD_DIR + "/arithmetic.jar").toAbsolutePath();
+ Path output = working.resolve("output.zip");
+ FileUtils.writeTextFile(
+ flagsFile,
+ "--output",
+ "output.zip",
+ "--min-api",
+ "24",
+ input.toString());
+ assertEquals(0, ToolHelper.forkD8(working, "@flags.txt").exitCode);
+ assertTrue(Files.exists(output));
+ Marker marker = ExtractMarker.extractMarkerFromDexFile(output);
+ assertEquals(24, marker.getMinApi().intValue());
+ assertEquals(Tool.D8, marker.getTool());
+ }
+
+ @Test(expected=CompilationFailedException.class)
+ public void nonExistingFlagsFile() throws Throwable {
+ Path working = temp.getRoot().toPath();
+ Path flags = working.resolve("flags.txt").toAbsolutePath();
+ assertNotEquals(0, ToolHelper.forkR8(working, "@flags.txt").exitCode);
+ DiagnosticsChecker.checkErrorsContains("File not found", handler ->
+ D8.run(
+ D8Command.parse(
+ new String[] { "@" + flags.toString() },
+ EmbeddedOrigin.INSTANCE,
+ handler).build()));
+ }
+
+ @Test
public void printsHelpOnNoInput() throws Throwable {
ProcessResult result = ToolHelper.forkD8(temp.getRoot().toPath());
assertFalse(result.exitCode == 0);
@@ -418,6 +456,17 @@
.build()));
}
+ @Test
+ public void noInputOutputsEmptyZip() throws CompilationFailedException, IOException {
+ Path emptyZip = temp.getRoot().toPath().resolve("empty.zip");
+ D8.run(
+ D8Command.builder()
+ .setOutput(emptyZip, OutputMode.DexIndexed)
+ .build());
+ assertTrue(Files.exists(emptyZip));
+ assertEquals(0, new ZipFile(emptyZip.toFile()).size());
+ }
+
private D8Command parse(String... args) throws CompilationFailedException {
return D8Command.parse(args, EmbeddedOrigin.INSTANCE).build();
}
diff --git a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
index dc4a9b4..1d9ec50 100644
--- a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
@@ -119,7 +119,7 @@
}
private AndroidApp mergeDexResources(int minAPILevel, List<ProgramResource> individalDexes)
- throws IOException, CompilationException, CompilationFailedException, ResourceException {
+ throws IOException, CompilationFailedException, ResourceException {
D8Command.Builder builder = D8Command.builder()
.setMinApiLevel(minAPILevel);
for (ProgramResource resource : individalDexes) {
diff --git a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
index 77959d9..ede7e53 100644
--- a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
@@ -76,7 +76,7 @@
// compilation should have failed on CompilationError since A is declaring a default method.
Assert.fail();
- } catch (CompilationError | CompilationException e) {
+ } catch (CompilationError e) {
// Expected.
}
}
diff --git a/src/test/java/com/android/tools/r8/DiagnosticsChecker.java b/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
index 2265c3e..2f45ae2 100644
--- a/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
+++ b/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
@@ -49,13 +49,14 @@
try {
runner.run(handler);
} catch (CompilationFailedException e) {
+ List<String> messages = ListUtils.map(handler.errors, Diagnostic::getDiagnosticMessage);
System.out.println("Expecting match for '" + snippet + "'");
- System.out.println("StdErr:\n" + handler.errors);
+ System.out.println("StdErr:\n" + messages);
assertTrue(
"Expected to find snippet '"
+ snippet
+ "' in error messages:\n"
- + String.join("\n", ListUtils.map(handler.errors, Diagnostic::getDiagnosticMessage)),
+ + String.join("\n", messages),
handler.errors.stream().anyMatch(d -> d.getDiagnosticMessage().contains(snippet)));
throw e;
}
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index a89cbd4..fbd88be 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -11,9 +11,12 @@
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.utils.FileUtils;
import com.google.common.collect.ImmutableList;
+import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -21,6 +24,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.zip.ZipFile;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -88,6 +92,43 @@
}
@Test
+ public void flagsFile() throws Throwable {
+ Path working = temp.getRoot().toPath();
+ Path library = ToolHelper.getDefaultAndroidJar();
+ Path input = Paths.get(EXAMPLES_BUILD_DIR + "/arithmetic.jar").toAbsolutePath();
+ Path output = working.resolve("output.zip");
+ Path flagsFile = working.resolve("flags.txt");
+ FileUtils.writeTextFile(
+ flagsFile,
+ "--output",
+ "output.zip",
+ "--min-api",
+ "24",
+ "--lib",
+ library.toAbsolutePath().toString(),
+ input.toString());
+ assertEquals(0, ToolHelper.forkR8(working, "@flags.txt").exitCode);
+ assertTrue(Files.exists(output));
+ Marker marker = ExtractMarker.extractMarkerFromDexFile(output);
+ assertEquals(24, marker.getMinApi().intValue());
+ assertEquals(Tool.R8, marker.getTool());
+ }
+
+
+ @Test(expected=CompilationFailedException.class)
+ public void nonExistingFlagsFile() throws Throwable {
+ Path working = temp.getRoot().toPath();
+ Path flags = working.resolve("flags.txt").toAbsolutePath();
+ assertNotEquals(0, ToolHelper.forkR8(working, "@flags.txt").exitCode);
+ DiagnosticsChecker.checkErrorsContains("File not found", handler ->
+ R8.run(
+ R8Command.parse(
+ new String[] { "@" + flags.toString() },
+ EmbeddedOrigin.INSTANCE,
+ handler).build()));
+ }
+
+ @Test
public void printsHelpOnNoInput() throws Throwable {
ProcessResult result = ToolHelper.forkR8(temp.getRoot().toPath());
assertFalse(result.exitCode == 0);
@@ -258,24 +299,6 @@
}
@Test
- public void argumentsInFile() throws Throwable {
- Path inputFile = temp.newFile("foobar.class").toPath();
- Path pgConfFile = temp.newFile("pgconf.config").toPath();
- Path argsFile = temp.newFile("more-args.txt").toPath();
- FileUtils.writeTextFile(argsFile, ImmutableList.of(
- "--debug --no-minification",
- "--pg-conf " + pgConfFile,
- inputFile.toString()
- ));
- R8Command command = parse("@" + argsFile.toString());
- assertEquals(CompilationMode.DEBUG, command.getMode());
- assertFalse(command.getEnableMinification());
- assertFalse(
- command.getEnableTreeShaking()); // We have no keep rules (proguard config file is empty).
- assertEquals(1, ToolHelper.getApp(command).getClassProgramResourcesForTesting().size());
- }
-
- @Test
public void nonExistingOutputJar() throws Throwable {
Path nonExistingJar = temp.getRoot().toPath().resolve("non-existing-archive.jar");
R8Command.builder().setOutput(nonExistingJar, OutputMode.DexIndexed).build();
@@ -428,6 +451,17 @@
assertTrue(result.stdout.contains("-printconfiguration"));
}
+ @Test
+ public void noInputOutputsEmptyZip() throws CompilationFailedException, IOException {
+ Path emptyZip = temp.getRoot().toPath().resolve("empty.zip");
+ R8.run(
+ R8Command.builder()
+ .setOutput(emptyZip, OutputMode.DexIndexed)
+ .build());
+ assertTrue(Files.exists(emptyZip));
+ assertEquals(0, new ZipFile(emptyZip.toFile()).size());
+ }
+
private R8Command parse(String... args) throws CompilationFailedException {
return R8Command.parse(args, EmbeddedOrigin.INSTANCE).build();
}
diff --git a/src/test/java/com/android/tools/r8/R8EntryPointTests.java b/src/test/java/com/android/tools/r8/R8EntryPointTests.java
index 6f3473e..edf7f20 100644
--- a/src/test/java/com/android/tools/r8/R8EntryPointTests.java
+++ b/src/test/java/com/android/tools/r8/R8EntryPointTests.java
@@ -131,8 +131,7 @@
Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
}
- private R8Command getCommand(Path out)
- throws CompilationException, IOException, CompilationFailedException {
+ private R8Command getCommand(Path out) throws IOException, CompilationFailedException {
return R8Command.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addProgramFiles(INPUT_JAR)
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index b27569b..b12eb2d 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -1388,7 +1388,7 @@
boolean disableInlining,
boolean disableClassInlining,
boolean hasMissingClasses)
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException,
+ throws IOException, ProguardRuleParserException, ExecutionException,
CompilationFailedException {
executeCompilerUnderTest(compilerUnderTest, fileNames, resultPath, compilationMode, null,
disableInlining, disableClassInlining, hasMissingClasses);
@@ -1403,7 +1403,7 @@
boolean disableInlining,
boolean disableClassInlining,
boolean hasMissingClasses)
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException,
+ throws IOException, ProguardRuleParserException, ExecutionException,
CompilationFailedException {
assert mode != null;
switch (compilerUnderTest) {
@@ -1434,7 +1434,7 @@
}
}
} catch (ResourceException e) {
- throw new CompilationException(e);
+ throw new CompilationError("", e);
}
}
}
@@ -1621,7 +1621,7 @@
protected void runJctfTest(CompilerUnderTest compilerUnderTest, String classFilePath,
String fullClassName)
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException,
+ throws IOException, ProguardRuleParserException, ExecutionException,
CompilationFailedException {
DexVm dexVm = ToolHelper.getDexVm();
@@ -1751,7 +1751,7 @@
CompilationMode mode,
DexVm dexVm,
File resultDir)
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException,
+ throws IOException, ProguardRuleParserException, ExecutionException,
CompilationFailedException {
executeCompilerUnderTest(compilerUnderTest, fileNames, resultDir.getAbsolutePath(), mode,
specification.disableInlining, specification.disableClassInlining,
@@ -1930,7 +1930,7 @@
compilerUnderTest, fileNames, resultDir.getCanonicalPath(), compilationMode,
specification.disableInlining, specification.disableClassInlining,
specification.hasMissingClasses);
- } catch (CompilationException | CompilationFailedException e) {
+ } catch (CompilationFailedException e) {
throw new CompilationError(e.getMessage(), e);
} catch (ExecutionException e) {
throw e.getCause();
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index 913278a..d8b886c 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -27,10 +27,12 @@
@Parameters(name = "{0}_{1}_{2}_{3}_{5}_{6}")
public static Collection<String[]> data() {
String[] tests = {
+ "abstractmethodremoval.AbstractMethodRemoval",
"arithmetic.Arithmetic",
"arrayaccess.ArrayAccess",
"barray.BArray",
"bridge.BridgeMethod",
+ "catchhandleroverlap.CatchHandlerOverlap",
"cse.CommonSubexpressionElimination",
"constants.Constants",
"controlflow.ControlFlow",
diff --git a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
index a504c7c..36a4f00 100644
--- a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
+++ b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
@@ -30,7 +30,7 @@
@Ignore
@Test
- public void UnreachableCode() throws IOException, ExecutionException, CompilationException {
+ public void UnreachableCode() throws IOException, ExecutionException {
String name = "unreachable-code-1";
AndroidApp input =
AndroidApp.builder()
diff --git a/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java b/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java
index 301f78f..d21d156 100644
--- a/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java
+++ b/src/test/java/com/android/tools/r8/ResourceShrinkerTest.java
@@ -73,8 +73,7 @@
}
@Test
- public void testEmptyClass()
- throws CompilationFailedException, IOException, ExecutionException, CompilationException {
+ public void testEmptyClass() throws CompilationFailedException, IOException, ExecutionException {
TrackAll analysis = runAnalysis(EmptyClass.class);
assertThat(analysis.integers, is(Sets.newHashSet()));
@@ -95,7 +94,7 @@
@Test
public void testConstsAndFieldAndMethods()
- throws CompilationFailedException, IOException, ExecutionException, CompilationException {
+ throws CompilationFailedException, IOException, ExecutionException {
TrackAll analysis = runAnalysis(ConstInCode.class);
assertThat(analysis.integers, is(Sets.newHashSet(10, 11)));
@@ -125,7 +124,7 @@
@Test
public void testStaticValues()
- throws CompilationFailedException, IOException, ExecutionException, CompilationException {
+ throws CompilationFailedException, IOException, ExecutionException {
TrackAll analysis = runAnalysis(StaticFields.class);
assertThat(analysis.integers, hasItems(10, 11, 12, 13));
@@ -163,8 +162,7 @@
}
@Test
- public void testAnnotations()
- throws CompilationFailedException, IOException, ExecutionException, CompilationException {
+ public void testAnnotations() throws CompilationFailedException, IOException, ExecutionException {
TrackAll analysis = runAnalysis(IntAnnotation.class, OuterAnnotation.class, Annotated.class);
assertThat(analysis.integers, hasItems(10, 11, 12, 13, 14, 15, 42));
@@ -184,7 +182,7 @@
@Test
public void testWithSkippingSome()
- throws ExecutionException, CompilationFailedException, CompilationException, IOException {
+ throws ExecutionException, CompilationFailedException, IOException {
TrackAll analysis = runAnalysis(ResourceClassToSkip.class, ToProcess.class);
assertThat(analysis.integers, hasItems(10, 11, 12));
@@ -222,13 +220,13 @@
}
private TrackAll runAnalysis(Class<?>... classes)
- throws IOException, CompilationException, ExecutionException, CompilationFailedException {
+ throws IOException, ExecutionException, CompilationFailedException {
AndroidApp app = readClasses(classes);
return runOnApp(app);
}
private TrackAll runOnApp(AndroidApp app)
- throws IOException, ExecutionException, CompilationFailedException, CompilationException {
+ throws IOException, ExecutionException, CompilationFailedException {
AndroidApp outputApp = compileWithD8(app);
Path outputDex = tmp.newFolder().toPath().resolve("classes.dex");
outputApp.writeToDirectory(outputDex.getParent(), OutputMode.DexIndexed);
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 96591d8..331af0a 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -215,7 +215,7 @@
* Compile an application with D8.
*/
protected AndroidApp compileWithD8(AndroidApp app)
- throws CompilationException, ExecutionException, IOException, CompilationFailedException {
+ throws ExecutionException, IOException, CompilationFailedException {
D8Command.Builder builder = ToolHelper.prepareD8CommandBuilder(app);
AndroidAppConsumers appSink = new AndroidAppConsumers(builder);
D8.run(builder.build());
@@ -226,7 +226,7 @@
* Compile an application with D8.
*/
protected AndroidApp compileWithD8(AndroidApp app, Consumer<InternalOptions> optionsConsumer)
- throws CompilationException, ExecutionException, IOException, CompilationFailedException {
+ throws ExecutionException, IOException, CompilationFailedException {
return ToolHelper.runD8(app, optionsConsumer);
}
@@ -234,7 +234,7 @@
* Compile an application with R8.
*/
protected AndroidApp compileWithR8(Class... classes)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
return ToolHelper.runR8(readClasses(classes));
}
@@ -243,7 +243,7 @@
* Compile an application with R8.
*/
protected AndroidApp compileWithR8(List<Class> classes)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
R8Command command = ToolHelper.prepareR8CommandBuilder(readClasses(classes)).build();
return ToolHelper.runR8(command);
@@ -253,7 +253,7 @@
* Compile an application with R8.
*/
protected AndroidApp compileWithR8(List<Class> classes, Consumer<InternalOptions> optionsConsumer)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
R8Command command = ToolHelper.prepareR8CommandBuilder(readClasses(classes)).build();
return ToolHelper.runR8(command, optionsConsumer);
@@ -263,7 +263,7 @@
* Compile an application with R8.
*/
protected AndroidApp compileWithR8(AndroidApp app)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
R8Command command = ToolHelper.prepareR8CommandBuilder(app).build();
return ToolHelper.runR8(command);
@@ -273,7 +273,7 @@
* Compile an application with R8.
*/
protected AndroidApp compileWithR8(AndroidApp app, Consumer<InternalOptions> optionsConsumer)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
R8Command command = ToolHelper.prepareR8CommandBuilder(app).build();
return ToolHelper.runR8(command, optionsConsumer);
@@ -283,7 +283,7 @@
* Compile an application with R8 using the supplied proguard configuration.
*/
protected AndroidApp compileWithR8(List<Class> classes, String proguardConfig)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
return compileWithR8(readClasses(classes), proguardConfig);
}
@@ -293,7 +293,7 @@
*/
protected AndroidApp compileWithR8(
List<Class> classes, String proguardConfig, Consumer<InternalOptions> optionsConsumer)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
return compileWithR8(readClasses(classes), proguardConfig, optionsConsumer);
}
@@ -302,7 +302,7 @@
* Compile an application with R8 using the supplied proguard configuration.
*/
protected AndroidApp compileWithR8(List<Class> classes, Path proguardConfig)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
return compileWithR8(readClasses(classes), proguardConfig);
}
@@ -311,7 +311,7 @@
* Compile an application with R8 using the supplied proguard configuration.
*/
protected AndroidApp compileWithR8(AndroidApp app, Path proguardConfig)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
R8Command command =
ToolHelper.prepareR8CommandBuilder(app)
@@ -324,7 +324,7 @@
* Compile an application with R8 using the supplied proguard configuration.
*/
protected AndroidApp compileWithR8(AndroidApp app, String proguardConfig)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
return compileWithR8(app, proguardConfig, null);
}
@@ -334,7 +334,7 @@
*/
protected AndroidApp compileWithR8(
AndroidApp app, String proguardConfig, Consumer<InternalOptions> optionsConsumer)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
R8Command command =
ToolHelper.prepareR8CommandBuilder(app)
@@ -348,7 +348,7 @@
*/
protected AndroidApp compileWithR8(
AndroidApp app, Path proguardConfig, Consumer<InternalOptions> optionsConsumer)
- throws CompilationException, ProguardRuleParserException, ExecutionException, IOException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
R8Command command =
ToolHelper.prepareR8CommandBuilder(app)
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index afa8c12..45ec280 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.DeviceRunner.DeviceRunnerConfigurationException;
import com.android.tools.r8.ToolHelper.DexVm.Kind;
import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexItemFactory;
@@ -768,7 +767,7 @@
public static ProguardConfiguration loadProguardConfiguration(
DexItemFactory factory, List<Path> configPaths)
- throws IOException, ProguardRuleParserException, CompilationException {
+ throws IOException, ProguardRuleParserException {
Reporter reporter = new Reporter(new DefaultDiagnosticsHandler());
if (configPaths.isEmpty()) {
return ProguardConfiguration.defaultConfiguration(factory, reporter);
@@ -789,7 +788,7 @@
return R8Command.builder(app).setProgramConsumer(DexIndexedConsumer.emptyConsumer());
}
- public static AndroidApp runR8(AndroidApp app) throws IOException, CompilationException {
+ public static AndroidApp runR8(AndroidApp app) throws IOException {
try {
return runR8(prepareR8CommandBuilder(app).build());
} catch (CompilationFailedException e) {
@@ -798,7 +797,7 @@
}
public static AndroidApp runR8(AndroidApp app, Consumer<InternalOptions> optionsConsumer)
- throws IOException, CompilationException {
+ throws IOException {
try {
return runR8(prepareR8CommandBuilder(app).build(), optionsConsumer);
} catch (CompilationFailedException e) {
@@ -806,18 +805,17 @@
}
}
- public static AndroidApp runR8(R8Command command) throws IOException, CompilationException {
+ public static AndroidApp runR8(R8Command command) throws IOException {
return runR8(command, null);
}
public static AndroidApp runR8(R8Command command, Consumer<InternalOptions> optionsConsumer)
- throws IOException, CompilationException {
+ throws IOException {
return runR8WithFullResult(command, optionsConsumer);
}
public static AndroidApp runR8WithFullResult(
- R8Command command, Consumer<InternalOptions> optionsConsumer)
- throws IOException, CompilationException {
+ R8Command command, Consumer<InternalOptions> optionsConsumer) throws IOException {
// TODO(zerny): Should we really be adding the android library in ToolHelper?
AndroidApp app = command.getInputApp();
if (app.getLibraryResourceProviders().isEmpty()) {
@@ -848,12 +846,12 @@
ImmutableList.of("!junit/**", "!android/test/**"))));
}
- public static AndroidApp runD8(AndroidApp app) throws CompilationException, IOException {
+ public static AndroidApp runD8(AndroidApp app) throws IOException {
return runD8(app, null);
}
public static AndroidApp runD8(AndroidApp app, Consumer<InternalOptions> optionsConsumer)
- throws CompilationException, IOException {
+ throws IOException {
try {
return runD8(D8Command.builder(app), optionsConsumer);
} catch (CompilationFailedException e) {
@@ -862,13 +860,13 @@
}
public static AndroidApp runD8(D8Command.Builder builder)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
return runD8(builder, null);
}
public static AndroidApp runD8(
D8Command.Builder builder, Consumer<InternalOptions> optionsConsumer)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
AndroidAppConsumers compatSink = new AndroidAppConsumers(builder);
D8Command command = builder.build();
InternalOptions options = command.getInternalOptions();
@@ -1328,6 +1326,12 @@
return builder;
}
+ public static R8Command.Builder allowPartiallyImplementedProguardOptions(
+ R8Command.Builder builder) {
+ builder.allowPartiallyImplementedProguardOptions();
+ return builder;
+ }
+
public static AndroidApp getApp(BaseCommand command) {
return command.getInputApp();
}
@@ -1354,7 +1358,7 @@
}
public static void writeApplication(DexApplication application, InternalOptions options)
- throws ExecutionException, DexOverflowException {
+ throws ExecutionException {
R8.writeApplication(
Executors.newSingleThreadExecutor(),
application,
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
index 5ec1bce..cc8633e4 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
@@ -432,7 +432,7 @@
assertEquals(0, javaResult.exitCode);
AndroidApp processedApp = compileWithR8(jasminBuilder.build(), proguardConfig,
- // Disable inlining to avoid the (short) tested method from being inlined then removed.
+ // Disable inlining to avoid the (short) tested method from being inlined and then removed.
internalOptions -> internalOptions.enableInlining = false);
// Run processed (output) program on ART
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
index 35a7613..60df7d2 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
@@ -109,7 +109,7 @@
assertEquals(0, javaResult.exitCode);
AndroidApp optimizedApp = compileWithR8(jasminBuilder.build(), proguardConfig,
- // Disable inlining to avoid the (short) tested method from being inlined then removed.
+ // Disable inlining to avoid the (short) tested method from being inlined and then removed.
internalOptions -> internalOptions.enableInlining = false);
// Run optimized (output) program on ART
diff --git a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
index c6a2bd3..d5d2c39 100644
--- a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
@@ -6,7 +6,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
@@ -43,7 +42,7 @@
}
private void runR8(Path proguardConfig, Consumer<InternalOptions> optionsConsumer)
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException,
+ throws IOException, ProguardRuleParserException, ExecutionException,
CompilationFailedException {
ToolHelper.runR8(
R8Command.builder()
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
index 479a558..d0ad1df 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoTestBase.java
@@ -5,7 +5,6 @@
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
@@ -32,8 +31,7 @@
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
- static AndroidApp compileWithD8(Class... classes) throws CompilationException, IOException,
- CompilationFailedException {
+ static AndroidApp compileWithD8(Class... classes) throws IOException, CompilationFailedException {
D8Command.Builder builder = D8Command.builder();
for (Class clazz : classes) {
builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz));
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index 89935a7..ead9175 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.code.ConstString;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
@@ -108,8 +107,7 @@
}
@Test
- public void manyFilesWithSharedSynthesizedClass()
- throws ExecutionException, IOException, DexOverflowException {
+ public void manyFilesWithSharedSynthesizedClass() throws ExecutionException, IOException {
// Create classes that all reference enough strings to overflow the index, but are all
// at different offsets in the strings array. This ensures we trigger multiple rounds of
diff --git a/src/test/java/com/android/tools/r8/dexfilemerger/DexFileMergerTests.java b/src/test/java/com/android/tools/r8/dexfilemerger/DexFileMergerTests.java
index 2b2a40b..4b3f4fe 100644
--- a/src/test/java/com/android/tools/r8/dexfilemerger/DexFileMergerTests.java
+++ b/src/test/java/com/android/tools/r8/dexfilemerger/DexFileMergerTests.java
@@ -6,7 +6,6 @@
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.DexFileMergerHelper;
@@ -39,7 +38,7 @@
@Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
private Path createMergerInputWithTwoClasses(OutputMode outputMode, boolean addMarker)
- throws CompilationFailedException, CompilationException, IOException {
+ throws CompilationFailedException, IOException {
// Compile Class1 and Class2
Path mergerInputZip = temp.newFolder().toPath().resolve("merger-input.zip");
D8Command command =
@@ -55,8 +54,7 @@
}
private void testMarker(boolean addMarkerToInput)
- throws CompilationFailedException, CompilationException, IOException, ResourceException,
- ExecutionException {
+ throws CompilationFailedException, IOException, ResourceException, ExecutionException {
Path mergerInputZip = createMergerInputWithTwoClasses(OutputMode.DexIndexed, addMarkerToInput);
Marker inputMarker = ExtractMarker.extractMarkerFromDexFile(mergerInputZip);
@@ -74,20 +72,18 @@
@Test
public void testMarkerPreserved()
- throws CompilationFailedException, CompilationException, IOException, ResourceException,
- ExecutionException {
+ throws CompilationFailedException, IOException, ResourceException, ExecutionException {
testMarker(true);
}
@Test
public void testMarkerNotAdded()
- throws CompilationFailedException, CompilationException, IOException, ResourceException,
- ExecutionException {
+ throws CompilationFailedException, IOException, ResourceException, ExecutionException {
testMarker(false);
}
@Test
- public void mergeTwoFiles() throws CompilationFailedException, CompilationException, IOException {
+ public void mergeTwoFiles() throws CompilationFailedException, IOException {
Path mergerInputZip = createMergerInputWithTwoClasses(OutputMode.DexFilePerClassFile, false);
Path mergerOutputZip = temp.getRoot().toPath().resolve("merger-out.zip");
@@ -107,7 +103,7 @@
}
private void generateClassesAndTest(int extraMethodCount, int programResourcesSize)
- throws IOException, ExecutionException, CompilationException, CompilationFailedException {
+ throws IOException, ExecutionException, CompilationFailedException {
AndroidApp generatedApp =
MainDexListTests.generateApplication(
ImmutableList.of("A", "B"),
@@ -125,8 +121,7 @@
}
@Test(expected = CompilationFailedException.class)
- public void failIfTooBig()
- throws IOException, ExecutionException, CompilationException, CompilationFailedException {
+ public void failIfTooBig() throws IOException, ExecutionException, CompilationFailedException {
// Generates an application with two classes, each with the number of methods just enough not to
// fit into a single dex file.
generateClassesAndTest(1, 2);
@@ -134,7 +129,7 @@
@Test
public void failIfTooBigControl()
- throws IOException, ExecutionException, CompilationException, CompilationFailedException {
+ throws IOException, ExecutionException, CompilationFailedException {
// Control test for failIfTooBig to make sure we don't fail with less methods.
generateClassesAndTest(0, 1);
}
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
index 5bbb9d5..a0b2515 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
@@ -8,7 +8,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.DexSplitterHelper;
@@ -56,7 +55,7 @@
@Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
private Path createInput(boolean dontCreateMarkerInD8)
- throws IOException, CompilationFailedException, CompilationException {
+ throws IOException, CompilationFailedException {
// Initial normal compile to create dex files.
Path inputZip = temp.newFolder().toPath().resolve("input.zip");
D8Command command =
@@ -76,8 +75,7 @@
}
private void testMarker(boolean addMarkerToInput)
- throws CompilationFailedException, CompilationException, IOException, ResourceException,
- ExecutionException {
+ throws CompilationFailedException, IOException, ResourceException, ExecutionException {
Path inputZip = createInput(!addMarkerToInput);
Path output = temp.newFolder().toPath().resolve("output");
@@ -102,15 +100,13 @@
@Test
public void testMarkerPreserved()
- throws CompilationFailedException, CompilationException, IOException, ResourceException,
- ExecutionException {
+ throws CompilationFailedException, IOException, ResourceException, ExecutionException {
testMarker(true);
}
@Test
public void testMarkerNotAdded()
- throws CompilationFailedException, CompilationException, IOException, ResourceException,
- ExecutionException {
+ throws CompilationFailedException, IOException, ResourceException, ExecutionException {
testMarker(false);
}
@@ -124,14 +120,13 @@
@Test
public void splitFilesNoObfuscation()
throws CompilationFailedException, IOException, FeatureMappingException, ResourceException,
- CompilationException, ExecutionException {
+ ExecutionException {
noObfuscation(false);
noObfuscation(true);
}
private void noObfuscation(boolean useOptions)
- throws IOException, CompilationFailedException, FeatureMappingException,
- ResourceException, ExecutionException, CompilationException {
+ throws IOException, CompilationFailedException, FeatureMappingException {
Path inputZip = createInput(false);
Path output = temp.newFolder().toPath().resolve("output");
Files.createDirectory(output);
@@ -228,7 +223,7 @@
@Test
public void splitFilesFromJar()
throws IOException, CompilationFailedException, FeatureMappingException, ResourceException,
- CompilationException, ExecutionException {
+ ExecutionException {
splitFromJars(true, true);
splitFromJars(false, true);
splitFromJars(true, false);
@@ -236,8 +231,7 @@
}
private void splitFromJars(boolean useOptions, boolean explicitBase)
- throws IOException, CompilationFailedException, FeatureMappingException, ResourceException,
- ExecutionException, CompilationException {
+ throws IOException, CompilationFailedException, FeatureMappingException {
Path inputZip = createInput(false);
Path output = temp.newFolder().toPath().resolve("output");
Files.createDirectory(output);
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 3cab10a..bda9ac5 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.smali.SmaliTestBase;
import com.android.tools.r8.utils.AndroidApp;
@@ -165,7 +164,7 @@
}
@Test
- public void lookupFieldWithDefaultInInterface() throws DexOverflowException {
+ public void lookupFieldWithDefaultInInterface() {
SmaliBuilder builder = new SmaliBuilder();
builder.addInterface("Interface");
diff --git a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
index a542b70..39c8d28 100644
--- a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
@@ -8,7 +8,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
@@ -64,14 +63,14 @@
String referenceApk,
String pgConf,
String input)
- throws ExecutionException, IOException, ProguardRuleParserException, CompilationException,
+ throws ExecutionException, IOException, ProguardRuleParserException,
CompilationFailedException {
return runAndCheckVerification(
compiler, mode, referenceApk, pgConf, null, Collections.singletonList(input));
}
public AndroidApp runAndCheckVerification(D8Command.Builder builder, String referenceApk)
- throws IOException, ExecutionException, CompilationException, CompilationFailedException {
+ throws IOException, ExecutionException, CompilationFailedException {
AndroidAppConsumers appSink = new AndroidAppConsumers(builder);
D8.run(builder.build());
AndroidApp result = appSink.build();
@@ -86,7 +85,7 @@
String pgConf,
Consumer<InternalOptions> optionsConsumer,
List<String> inputs)
- throws ExecutionException, IOException, ProguardRuleParserException, CompilationException,
+ throws ExecutionException, IOException, ProguardRuleParserException,
CompilationFailedException {
assertTrue(referenceApk == null || new File(referenceApk).exists());
AndroidAppConsumers outputApp;
@@ -99,6 +98,7 @@
builder.setMode(mode);
builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
builder.setMinApiLevel(AndroidApiLevel.L.getLevel());
+ ToolHelper.allowPartiallyImplementedProguardOptions(builder);
ToolHelper.addProguardConfigurationConsumer(
builder,
pgConfig -> {
diff --git a/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java b/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java
index e546607..ab430d5 100644
--- a/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.internal;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
@@ -19,7 +18,7 @@
private static final String JAR = "third_party/framework/framework_160115954.jar";
private AndroidApp doRun(D8Command.Builder builder)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
builder.setProgramConsumer(null);
AndroidAppConsumers appSink = new AndroidAppConsumers(builder);
D8.run(builder.build());
diff --git a/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java b/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java
index 0946ded..390105e 100644
--- a/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.internal;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
@@ -17,7 +16,7 @@
"third_party/photos/2017-06-06/PhotosEnglishOnlyLegacy_proguard.jar";
public void runD8AndCheckVerification(CompilationMode mode, String version)
- throws ProguardRuleParserException, ExecutionException, IOException, CompilationException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
runAndCheckVerification(CompilerUnderTest.D8, mode, version, null, version);
}
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreCompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/GMSCoreCompilationTestBase.java
index df4bbfe..f0b1ece 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreCompilationTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreCompilationTestBase.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.internal;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
@@ -33,14 +32,14 @@
static final String REFERENCE_APK = "noshrink_x86_GmsCore_prod_alldpi_release_unsigned.apk";
public void runR8AndCheckVerification(CompilationMode mode, String version)
- throws ProguardRuleParserException, ExecutionException, IOException, CompilationException,
+ throws ProguardRuleParserException, ExecutionException, IOException,
CompilationFailedException {
runAndCheckVerification(CompilerUnderTest.R8, mode, version);
}
public void runAndCheckVerification(
CompilerUnderTest compiler, CompilationMode mode, String version)
- throws ExecutionException, IOException, ProguardRuleParserException, CompilationException,
+ throws ExecutionException, IOException, ProguardRuleParserException,
CompilationFailedException {
runAndCheckVerification(
compiler, mode, version + GMSCORE_APK, null, Paths.get(version, GMSCORE_APK).toString());
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java
index 5f635ff..09ce657 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreDeployJarVerificationTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.internal;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
@@ -19,7 +18,7 @@
public AndroidApp buildFromDeployJar(
CompilerUnderTest compiler, CompilationMode mode, String base, boolean hasReference)
- throws ExecutionException, IOException, ProguardRuleParserException, CompilationException,
+ throws ExecutionException, IOException, ProguardRuleParserException,
CompilationFailedException {
return runAndCheckVerification(
compiler, mode, hasReference ? base + REFERENCE_APK : null, null, base + DEPLOY_JAR);
@@ -29,7 +28,7 @@
public AndroidApp buildFromDeployJar(
CompilerUnderTest compiler, CompilationMode mode, String base, boolean hasReference,
Consumer<InternalOptions> optionsConsumer)
- throws ExecutionException, IOException, ProguardRuleParserException, CompilationException,
+ throws ExecutionException, IOException, ProguardRuleParserException,
CompilationFailedException {
return runAndCheckVerification(
compiler,
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
index 5e1c61f..abc7a73 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.internal;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.OutputMode;
@@ -33,7 +32,7 @@
}
private AndroidApp doRun()
- throws IOException, ProguardRuleParserException, CompilationException, ExecutionException,
+ throws IOException, ProguardRuleParserException, ExecutionException,
CompilationFailedException {
R8Command command =
R8Command.builder()
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index 5afb068..d4ab6c6 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -37,7 +36,7 @@
return buildApplication(
AndroidApp.builder().addDexProgramData(builder.compile(), Origin.unknown()).build(),
options);
- } catch (IOException | RecognitionException | ExecutionException | DexOverflowException e) {
+ } catch (IOException | RecognitionException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@@ -118,8 +117,7 @@
return iterator;
}
- private AndroidApp writeDex(DexApplication application, InternalOptions options)
- throws DexOverflowException {
+ private AndroidApp writeDex(DexApplication application, InternalOptions options) {
try {
ToolHelper.writeApplication(application, options);
options.signalFinishedToConsumers();
@@ -129,7 +127,7 @@
}
}
- public String run() throws DexOverflowException, IOException {
+ public String run() throws IOException {
AppInfo appInfo = new AppInfo(application);
IRConverter converter = new IRConverter(appInfo, options);
converter.replaceCodeForTesting(method, code);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
index 967b33e..aefe665 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
@@ -7,9 +7,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo;
@@ -124,15 +122,11 @@
.method(
new MethodSignature("subtractConstants8bitRegisters", "int", ImmutableList.of()))
.getMethod();
- try {
- IRCode irCode = subtract.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, subtract, irCode);
- analysis.forEach((v, l) -> {
- assertEither(l, PRIMITIVE, NULL, TOP);
- });
- } catch (ApiLevelException e) {
- fail(e.getMessage());
- }
+ IRCode irCode = subtract.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, subtract, irCode);
+ analysis.forEach((v, l) -> {
+ assertEither(l, PRIMITIVE, NULL, TOP);
+ });
}
// A couple branches, along with some recursive calls.
@@ -142,15 +136,11 @@
inspector.clazz("Test")
.method(new MethodSignature("fibonacci", "int", ImmutableList.of("int")))
.getMethod();
- try {
- IRCode irCode = fib.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, fib, irCode);
- analysis.forEach((v, l) -> {
- assertEither(l, PRIMITIVE, NULL);
- });
- } catch (ApiLevelException e) {
- fail(e.getMessage());
- }
+ IRCode irCode = fib.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, fib, irCode);
+ analysis.forEach((v, l) -> {
+ assertEither(l, PRIMITIVE, NULL);
+ });
}
// fill-array-data
@@ -160,32 +150,28 @@
inspector.clazz("Test")
.method(new MethodSignature("test1", "int[]", ImmutableList.of()))
.getMethod();
- try {
- IRCode irCode = test1.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, test1, irCode);
- Value array = null;
- InstructionIterator iterator = irCode.instructionIterator();
- while (iterator.hasNext()) {
- Instruction instruction = iterator.next();
- if (instruction instanceof NewArrayEmpty) {
- array = instruction.outValue();
- break;
- }
+ IRCode irCode = test1.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, test1, irCode);
+ Value array = null;
+ InstructionIterator iterator = irCode.instructionIterator();
+ while (iterator.hasNext()) {
+ Instruction instruction = iterator.next();
+ if (instruction instanceof NewArrayEmpty) {
+ array = instruction.outValue();
+ break;
}
- assertNotNull(array);
- final Value finalArray = array;
- analysis.forEach((v, l) -> {
- if (v == finalArray) {
- assertTrue(l.isArrayTypeLatticeElement());
- ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
- assertTrue(lattice.getArrayType().isPrimitiveArrayType());
- assertEquals(1, lattice.getNesting());
- assertFalse(lattice.isNullable());
- }
- });
- } catch (ApiLevelException e) {
- fail(e.getMessage());
}
+ assertNotNull(array);
+ final Value finalArray = array;
+ analysis.forEach((v, l) -> {
+ if (v == finalArray) {
+ assertTrue(l.isArrayTypeLatticeElement());
+ ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
+ assertTrue(lattice.getArrayType().isPrimitiveArrayType());
+ assertEquals(1, lattice.getNesting());
+ assertFalse(lattice.isNullable());
+ }
+ });
}
// filled-new-array
@@ -195,32 +181,28 @@
inspector.clazz("Test")
.method(new MethodSignature("test4", "int[]", ImmutableList.of()))
.getMethod();
- try {
- IRCode irCode = test4.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, test4, irCode);
- Value array = null;
- InstructionIterator iterator = irCode.instructionIterator();
- while (iterator.hasNext()) {
- Instruction instruction = iterator.next();
- if (instruction instanceof InvokeNewArray) {
- array = instruction.outValue();
- break;
- }
+ IRCode irCode = test4.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, test4, irCode);
+ Value array = null;
+ InstructionIterator iterator = irCode.instructionIterator();
+ while (iterator.hasNext()) {
+ Instruction instruction = iterator.next();
+ if (instruction instanceof InvokeNewArray) {
+ array = instruction.outValue();
+ break;
}
- assertNotNull(array);
- final Value finalArray = array;
- analysis.forEach((v, l) -> {
- if (v == finalArray) {
- assertTrue(l.isArrayTypeLatticeElement());
- ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
- assertTrue(lattice.getArrayType().isPrimitiveArrayType());
- assertEquals(1, lattice.getNesting());
- assertFalse(lattice.isNullable());
- }
- });
- } catch (ApiLevelException e) {
- fail(e.getMessage());
}
+ assertNotNull(array);
+ final Value finalArray = array;
+ analysis.forEach((v, l) -> {
+ if (v == finalArray) {
+ assertTrue(l.isArrayTypeLatticeElement());
+ ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
+ assertTrue(lattice.getArrayType().isPrimitiveArrayType());
+ assertEquals(1, lattice.getNesting());
+ assertFalse(lattice.isNullable());
+ }
+ });
}
// Make sure the analysis does not hang.
@@ -230,20 +212,16 @@
inspector.clazz("Test")
.method(new MethodSignature("loop2", "void", ImmutableList.of()))
.getMethod();
- try {
- IRCode irCode = loop2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, loop2, irCode);
- analysis.forEach((v, l) -> {
- if (l.isClassTypeLatticeElement()) {
- ClassTypeLatticeElement lattice = l.asClassTypeLatticeElement();
- assertEquals("Ljava/io/PrintStream;", lattice.getClassType().toDescriptorString());
- // TODO(b/70795205): Can be refined by using control-flow info.
- assertTrue(l.isNullable());
- }
- });
- } catch (ApiLevelException e) {
- fail(e.getMessage());
- }
+ IRCode irCode = loop2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, loop2, irCode);
+ analysis.forEach((v, l) -> {
+ if (l.isClassTypeLatticeElement()) {
+ ClassTypeLatticeElement lattice = l.asClassTypeLatticeElement();
+ assertEquals("Ljava/io/PrintStream;", lattice.getClassType().toDescriptorString());
+ // TODO(b/70795205): Can be refined by using control-flow info.
+ assertTrue(l.isNullable());
+ }
+ });
}
// move-exception
@@ -253,19 +231,15 @@
inspector.clazz("Test")
.method(new MethodSignature("test2_throw", "int", ImmutableList.of()))
.getMethod();
- try {
- IRCode irCode = test2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, test2, irCode);
- analysis.forEach((v, l) -> {
- if (l.isClassTypeLatticeElement()) {
- ClassTypeLatticeElement lattice = l.asClassTypeLatticeElement();
- assertEquals("Ljava/lang/Throwable;", lattice.getClassType().toDescriptorString());
- assertFalse(l.isNullable());
- }
- });
- } catch (ApiLevelException e) {
- fail(e.getMessage());
- }
+ IRCode irCode = test2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, test2, irCode);
+ analysis.forEach((v, l) -> {
+ if (l.isClassTypeLatticeElement()) {
+ ClassTypeLatticeElement lattice = l.asClassTypeLatticeElement();
+ assertEquals("Ljava/lang/Throwable;", lattice.getClassType().toDescriptorString());
+ assertFalse(l.isNullable());
+ }
+ });
}
// One very complicated example.
@@ -283,13 +257,9 @@
ConstString.class, new ClassTypeLatticeElement(appInfo.dexItemFactory.stringType, false),
CheckCast.class, new ClassTypeLatticeElement(test, true),
NewInstance.class, new ClassTypeLatticeElement(test, false));
- try {
- IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
- analysis.forEach((v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
- } catch (ApiLevelException e) {
- fail(e.getMessage());
- }
+ IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
+ analysis.forEach((v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
}
// One more complicated example.
@@ -305,13 +275,9 @@
ConstString.class, new ClassTypeLatticeElement(appInfo.dexItemFactory.stringType, false),
InstanceOf.class, PRIMITIVE,
StaticGet.class, new ClassTypeLatticeElement(test, true));
- try {
- IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
- TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
- analysis.forEach((v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
- } catch (ApiLevelException e) {
- fail(e.getMessage());
- }
+ IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+ TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
+ analysis.forEach((v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
}
private static void assertEither(TypeLatticeElement actual, TypeLatticeElement... expected) {
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java b/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java
index 9c58d25..1f4d2ba 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.utils.DexInspector;
import java.util.Collections;
import org.junit.Assert;
-import org.junit.Ignore;
import org.junit.Test;
public class CovariantReturnTypeAnnotationTransformerTest extends AsmTestBase {
@@ -49,7 +48,6 @@
failsIndependentOfFlag(input);
}
- @Ignore("b/78618808")
@Test
public void testVersion2WithClient1And2() throws Exception {
AndroidApp input =
@@ -63,7 +61,6 @@
succeedsIndependentOfFlag(input, true);
}
- @Ignore("b/78618808")
@Test
public void testVersion2WithClient3() throws Exception {
AndroidApp input =
@@ -108,6 +105,23 @@
succeedsIndependentOfFlag(input, false);
}
+ @Test
+ public void testRepeatedCompilation() throws Exception {
+ AndroidApp input =
+ buildAndroidApp(
+ ToolHelper.getClassAsBytes(Client.class),
+ ToolHelper.getClassAsBytes(A.class),
+ com.android.tools.r8.ir.desugar.annotations.version2.BDump.dump(),
+ com.android.tools.r8.ir.desugar.annotations.version2.CDump.dump());
+
+ AndroidApp output =
+ compileWithD8(input, options -> options.processCovariantReturnTypeAnnotations = true);
+
+ // Compilation will fail with a compilation error the second time if the implementation does
+ // not remove the CovariantReturnType annotations properly during the first compilation.
+ compileWithD8(output, options -> options.processCovariantReturnTypeAnnotations = true);
+ }
+
private void succeedsWithOption(
AndroidApp input, boolean option, boolean checkPresenceOfSyntheticMethods) throws Exception {
AndroidApp output =
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
index 47f0db3..a5c7093 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
@@ -6,7 +6,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
@@ -99,8 +98,7 @@
});
}
- private Path runR8(Path proguardConfig)
- throws IOException, CompilationException, CompilationFailedException {
+ private Path runR8(Path proguardConfig) throws IOException, CompilationFailedException {
Path dexOutputDir = temp.newFolder().toPath();
ToolHelper.runR8(
R8Command.builder()
diff --git a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
index 990fe6e..7b74453 100644
--- a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
+++ b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jsr45;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
@@ -50,7 +49,7 @@
public TemporaryFolder tmpOutputDir = ToolHelper.getTemporaryFolderForTest();
private AndroidApp compileWithD8(Path intputPath, Path outputPath)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
D8Command.Builder builder =
D8Command.builder()
.setMinApiLevel(AndroidApiLevel.O.getLevel())
@@ -62,7 +61,7 @@
}
private AndroidApp compileWithR8(Path inputPath, Path outputPath, Path keepRulesPath)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
return ToolHelper.runR8(
R8Command.builder()
.addProgramFiles(inputPath)
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index bb83093..c175e04 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -49,6 +49,12 @@
// invoke the tested method.
private static final String JASMIN_MAIN_CLASS = "TestMain";
+ @Parameter(0) public boolean allowAccessModification;
+ @Parameter(1) public KotlinTargetVersion targetVersion;
+
+ private final List<Path> classpath = new ArrayList<>();
+ private final List<Path> extraClasspath = new ArrayList<>();
+
@Parameters(name = "allowAccessModification: {0} target: {1}")
public static Collection<Object[]> data() {
ImmutableList.Builder<Object[]> builder = new ImmutableList.Builder<>();
@@ -59,11 +65,6 @@
return builder.build();
}
- @Parameter(0) public boolean allowAccessModification;
- @Parameter(1) public KotlinTargetVersion targetVersion;
-
- private final List<Path> extraClasspath = new ArrayList<>();
-
protected void addExtraClasspath(Path path) {
extraClasspath.add(path);
}
@@ -111,47 +112,67 @@
}));
}
- protected static ClassSubject checkClassExists(DexInspector inspector, String className) {
+ protected ClassSubject checkClassIsKept(DexInspector inspector, String className) {
+ checkClassExistsInInput(className);
ClassSubject classSubject = inspector.clazz(className);
assertNotNull(classSubject);
assertTrue("No class " + className, classSubject.isPresent());
return classSubject;
}
- protected static FieldSubject checkFieldIsPresent(ClassSubject classSubject, String fieldType,
+ protected FieldSubject checkFieldIsKept(ClassSubject classSubject, String fieldType,
String fieldName) {
+ // Field must exist in the input.
+ checkFieldPresenceInInput(classSubject.getOriginalName(), fieldType, fieldName, true);
FieldSubject fieldSubject = classSubject.field(fieldType, fieldName);
assertTrue("No field " + fieldName + " in " + classSubject.getOriginalName(),
fieldSubject.isPresent());
return fieldSubject;
}
- protected static void checkFieldIsAbsent(ClassSubject classSubject, String fieldType,
+ protected void checkFieldIsAbsent(ClassSubject classSubject, String fieldType,
String fieldName) {
+ // Field must NOT exist in the input.
+ checkFieldPresenceInInput(classSubject.getOriginalName(), fieldType, fieldName, false);
FieldSubject fieldSubject = classSubject.field(fieldType, fieldName);
assertNotNull(fieldSubject);
assertFalse(fieldSubject.isPresent());
}
- protected static MethodSubject checkMethodIsPresent(ClassSubject classSubject,
+ protected void checkMethodIsAbsent(ClassSubject classSubject,
MethodSignature methodSignature) {
- return checkMethod(classSubject, methodSignature, true);
+ checkMethodPresenceInInput(classSubject.getOriginalName(), methodSignature, false);
+ checkMethodPresenceInOutput(classSubject, methodSignature, false);
}
- protected static void checkMethodIsAbsent(ClassSubject classSubject,
+ protected MethodSubject checkMethodIsKept(ClassSubject classSubject,
MethodSignature methodSignature) {
- checkMethod(classSubject, methodSignature, false);
+ checkMethodPresenceInInput(classSubject.getOriginalName(), methodSignature, true);
+ return checkMethodisKeptOrRemoved(classSubject, methodSignature, true);
}
- protected static MethodSubject checkMethod(ClassSubject classSubject,
+ protected void checkMethodIsRemoved(ClassSubject classSubject,
+ MethodSignature methodSignature) {
+ checkMethodPresenceInInput(classSubject.getOriginalName(), methodSignature, true);
+ checkMethodisKeptOrRemoved(classSubject, methodSignature, false);
+ }
+
+ protected MethodSubject checkMethodisKeptOrRemoved(ClassSubject classSubject,
+ MethodSignature methodSignature, boolean isPresent) {
+ checkMethodPresenceInInput(classSubject.getOriginalName(), methodSignature, true);
+ return checkMethodPresenceInOutput(classSubject, methodSignature, isPresent);
+ }
+
+ private MethodSubject checkMethodPresenceInOutput(ClassSubject classSubject,
MethodSignature methodSignature, boolean isPresent) {
MethodSubject methodSubject = classSubject.method(methodSignature);
assertNotNull(methodSubject);
+ String methodSig = methodSignature.name + methodSignature.toDescriptor();
if (isPresent) {
- assertTrue("No method " + methodSignature.name, methodSubject.isPresent());
+ assertTrue("No method " + methodSig + " in output", methodSubject.isPresent());
} else {
- assertFalse("Method " + methodSignature.name + " exists", methodSubject.isPresent());
+ assertFalse("Method " + methodSig + " exists in output", methodSubject.isPresent());
}
return methodSubject;
}
@@ -210,7 +231,7 @@
}
// Build classpath for compilation (and java execution)
- List<Path> classpath = new ArrayList<>(extraClasspath.size() + 1);
+ assert classpath.isEmpty();
classpath.add(getKotlinJarFile(folder));
classpath.add(getJavaJarFile(folder));
classpath.addAll(extraClasspath);
@@ -240,6 +261,36 @@
inspector.inspectApp(app);
}
+ protected void checkClassExistsInInput(String className) {
+ if (!AsmUtils.doesClassExist(classpath, className)) {
+ throw new AssertionError("Class " + className + " does not exist in input");
+ }
+ }
+
+ private void checkMethodPresenceInInput(String className, MethodSignature methodSignature,
+ boolean isPresent) {
+ boolean foundMethod = AsmUtils.doesMethodExist(classpath, className,
+ methodSignature.name, methodSignature.toDescriptor());
+ if (isPresent != foundMethod) {
+ throw new AssertionError(
+ "Method " + methodSignature.name + methodSignature.toDescriptor()
+ + " " + (foundMethod ? "exists" : "does not exist")
+ + " in input class " + className + " but is expected to be "
+ + (isPresent ? "present" : "absent"));
+ }
+ }
+
+ private void checkFieldPresenceInInput(String className, String fieldType, String fieldName,
+ boolean isPresent) {
+ boolean foundField = AsmUtils.doesFieldExist(classpath, className, fieldName, fieldType);
+ if (isPresent != foundField) {
+ throw new AssertionError(
+ "Field " + fieldName + " " + (foundField ? "exists" : "does not exist")
+ + " in input class " + className + " but is expected to be "
+ + (isPresent ? "present" : "absent"));
+ }
+ }
+
private Path getKotlinJarFile(String folder) {
return Paths.get(ToolHelper.TESTS_BUILD_DIR, "kotlinR8TestResources",
targetVersion.getFolderName(), folder + FileUtils.JAR_EXTENSION);
diff --git a/src/test/java/com/android/tools/r8/kotlin/AsmUtils.java b/src/test/java/com/android/tools/r8/kotlin/AsmUtils.java
new file mode 100644
index 0000000..7b7abcb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/AsmUtils.java
@@ -0,0 +1,144 @@
+// 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.kotlin;
+
+import com.android.tools.r8.utils.DescriptorUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Utilities to lookup symbols in a classpath using ASM.
+ */
+public final class AsmUtils {
+
+ private AsmUtils() {
+ }
+
+ public static boolean doesClassExist(List<Path> classpath, String className) {
+ byte[] classData = loadClassBytesFromClasspath(classpath, className);
+ return classData != null;
+ }
+
+ public static boolean doesMethodExist(List<Path> classpath, String className,
+ String methodName,
+ String methodDescriptor) {
+ MethodFinder classVisitor = new MethodFinder(methodName, methodDescriptor);
+ visitClass(classpath, className, classVisitor);
+ return classVisitor.foundMethod;
+ }
+
+ private static final class MethodFinder extends ClassVisitor {
+
+ private final String methodName;
+ private final String methodDescriptor;
+ public boolean foundMethod = false;
+
+ public MethodFinder(String methodName, String methodDescriptor) {
+ super(Opcodes.ASM6);
+ this.methodName = methodName;
+ this.methodDescriptor = methodDescriptor;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ if (name.equals(methodName) && desc.equals(methodDescriptor)) {
+ assert !foundMethod;
+ foundMethod = true;
+ }
+ return null;
+ }
+ }
+
+ public static boolean doesFieldExist(List<Path> classpath, String className,
+ String fieldName,
+ String fieldType) {
+ FieldFinder classVisitor = new FieldFinder(fieldName, fieldType);
+ visitClass(classpath, className, classVisitor);
+ return classVisitor.foundField;
+ }
+
+ private static final class FieldFinder extends ClassVisitor {
+
+ private final String fieldName;
+ private final String fieldDescriptor;
+ public boolean foundField = false;
+
+ public FieldFinder(String fieldName, String fieldType) {
+ super(Opcodes.ASM6);
+ this.fieldName = fieldName;
+ this.fieldDescriptor = DescriptorUtils.javaTypeToDescriptor(fieldType);
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value) {
+ if (name.equals(fieldName) && desc.equals(fieldDescriptor)) {
+ assert !foundField;
+ foundField = true;
+ }
+ return null;
+ }
+ }
+
+ private static void visitClass(List<Path> classpath, String className,
+ ClassVisitor classVisitor) {
+ byte[] classData = loadClassBytesFromClasspath(classpath, className);
+ new ClassReader(classData).accept(classVisitor,
+ ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+ }
+
+ private static byte[] loadClassBytesFromClasspath(List<Path> classpath, String className) {
+ String classFilename = DescriptorUtils.getPathFromJavaType(className);
+ for (Path path : classpath) {
+ if (path.toFile().getPath().endsWith(".jar")) {
+ try (JarInputStream jarInputStream = new JarInputStream(Files.newInputStream(path))) {
+ JarEntry jarEntry;
+ while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
+ if (jarEntry.isDirectory()) {
+ continue;
+ }
+ String entryName = jarEntry.getName();
+ if (entryName.equals(classFilename)) {
+ byte[] data = new byte[1024];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ while (true) {
+ int bytesRead = jarInputStream.read(data, 0, data.length);
+ if (bytesRead < 0) {
+ break;
+ }
+ baos.write(data, 0, bytesRead);
+ }
+ return baos.toByteArray();
+ }
+ }
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ } else if (path.toFile().getPath().endsWith(".class")) {
+ if (path.toFile().getPath().equals(classFilename)) {
+ try {
+ return Files.readAllBytes(path);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index df04931..7425082 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -66,9 +66,9 @@
"companionProperties_usePrimitiveProp");
runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
String propertyName = "primitiveProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, "int", propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, "int", propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getterAccessor = testedClass
@@ -78,12 +78,12 @@
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(outerClass, getterAccessor);
- checkMethodIsAbsent(outerClass, setterAccessor);
+ checkMethodIsRemoved(outerClass, getterAccessor);
+ checkMethodIsRemoved(outerClass, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(outerClass, getterAccessor);
- checkMethodIsPresent(outerClass, setterAccessor);
+ checkMethodIsKept(outerClass, getterAccessor);
+ checkMethodIsKept(outerClass, setterAccessor);
}
});
}
@@ -95,9 +95,9 @@
"companionProperties_usePrivateProp");
runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
String propertyName = "privateProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getterAccessor = testedClass
@@ -107,13 +107,13 @@
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(outerClass, getterAccessor);
- checkMethodIsAbsent(outerClass, setterAccessor);
+ checkMethodIsRemoved(outerClass, getterAccessor);
+ checkMethodIsRemoved(outerClass, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(outerClass, getterAccessor);
- checkMethodIsPresent(outerClass, setterAccessor);
+ checkMethodIsKept(outerClass, getterAccessor);
+ checkMethodIsKept(outerClass, setterAccessor);
}
});
}
@@ -125,9 +125,9 @@
"companionProperties_useInternalProp");
runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
String propertyName = "internalProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getterAccessor = testedClass
@@ -137,12 +137,12 @@
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(outerClass, getterAccessor);
- checkMethodIsAbsent(outerClass, setterAccessor);
+ checkMethodIsRemoved(outerClass, getterAccessor);
+ checkMethodIsRemoved(outerClass, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(outerClass, getterAccessor);
- checkMethodIsPresent(outerClass, setterAccessor);
+ checkMethodIsKept(outerClass, getterAccessor);
+ checkMethodIsKept(outerClass, setterAccessor);
}
});
}
@@ -154,9 +154,9 @@
"companionProperties_usePublicProp");
runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
String propertyName = "publicProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getterAccessor = testedClass
@@ -166,12 +166,12 @@
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(outerClass, getterAccessor);
- checkMethodIsAbsent(outerClass, setterAccessor);
+ checkMethodIsRemoved(outerClass, getterAccessor);
+ checkMethodIsRemoved(outerClass, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(outerClass, getterAccessor);
- checkMethodIsPresent(outerClass, setterAccessor);
+ checkMethodIsKept(outerClass, getterAccessor);
+ checkMethodIsKept(outerClass, setterAccessor);
}
});
}
@@ -183,9 +183,9 @@
"companionLateInitProperties_usePrivateLateInitProp");
runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
String propertyName = "privateLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getterAccessor = testedClass
@@ -194,12 +194,12 @@
.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(outerClass, getterAccessor);
- checkMethodIsAbsent(outerClass, setterAccessor);
+ checkMethodIsRemoved(outerClass, getterAccessor);
+ checkMethodIsRemoved(outerClass, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(outerClass, getterAccessor);
- checkMethodIsPresent(outerClass, setterAccessor);
+ checkMethodIsKept(outerClass, getterAccessor);
+ checkMethodIsKept(outerClass, setterAccessor);
}
});
}
@@ -211,10 +211,11 @@
"companionLateInitProperties_useInternalLateInitProp");
runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
String propertyName = "internalLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().accessFlags.isPublic());
MemberNaming.MethodSignature getterAccessor = testedClass
.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
@@ -234,10 +235,11 @@
"companionLateInitProperties_usePublicLateInitProp");
runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
String propertyName = "publicLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().accessFlags.isPublic());
MemberNaming.MethodSignature getterAccessor = testedClass
.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
@@ -257,49 +259,50 @@
"accessor_accessPropertyFromCompanionClass");
runTest("accessors", mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
- ClassSubject companionClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
+ ClassSubject companionClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "property";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
// The getter is always inlined since it just calls into the accessor.
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
- checkMethodIsAbsent(companionClass, getter);
+ checkMethodIsRemoved(companionClass, getter);
MemberNaming.MethodSignature getterAccessor =
testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(outerClass, getterAccessor);
+ checkMethodIsRemoved(outerClass, getterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(outerClass, getterAccessor);
+ checkMethodIsKept(outerClass, getterAccessor);
}
});
}
@Test
+ @Ignore("b/74103342")
public void testAccessorFromPrivate() throws Exception {
TestKotlinCompanionClass testedClass = ACCESSOR_COMPANION_PROPERTY_CLASS;
String mainClass = addMainToClasspath("accessors.AccessorKt",
"accessor_accessPropertyFromOuterClass");
runTest("accessors", mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
- ClassSubject companionClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
+ ClassSubject companionClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "property";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
// We cannot inline the getter because we don't know if NPE is preserved.
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
- checkMethodIsPresent(companionClass, getter);
+ checkMethodIsKept(companionClass, getter);
// We should always inline the static accessor method.
MemberNaming.MethodSignature getterAccessor =
testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
- checkMethodIsAbsent(outerClass, getterAccessor);
+ checkMethodIsRemoved(companionClass, getterAccessor);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
@@ -316,7 +319,7 @@
"noUseOfPropertyAccessorFromInnerClass");
runTest("accessors", mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName());
for (String propertyName : testedClass.properties.keySet()) {
MemberNaming.MethodSignature getterAccessor =
@@ -324,8 +327,8 @@
MemberNaming.MethodSignature setterAccessor =
testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
- checkMethodIsAbsent(classSubject, getterAccessor);
- checkMethodIsAbsent(classSubject, setterAccessor);
+ checkMethodIsRemoved(classSubject, getterAccessor);
+ checkMethodIsRemoved(classSubject, setterAccessor);
}
});
}
@@ -338,10 +341,10 @@
"usePrivatePropertyAccessorFromInnerClass");
runTest("accessors", mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "privateProp";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING,
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING,
propertyName);
assertFalse(fieldSubject.getField().accessFlags.isStatic());
@@ -351,12 +354,12 @@
testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getterAccessor);
- checkMethodIsAbsent(classSubject, setterAccessor);
+ checkMethodIsRemoved(classSubject, getterAccessor);
+ checkMethodIsRemoved(classSubject, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getterAccessor);
- checkMethodIsPresent(classSubject, setterAccessor);
+ checkMethodIsKept(classSubject, getterAccessor);
+ checkMethodIsKept(classSubject, setterAccessor);
}
});
}
@@ -369,10 +372,10 @@
"usePrivateLateInitPropertyAccessorFromInnerClass");
runTest("accessors", mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "privateLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING,
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING,
propertyName);
assertFalse(fieldSubject.getField().accessFlags.isStatic());
@@ -382,12 +385,12 @@
testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getterAccessor);
- checkMethodIsAbsent(classSubject, setterAccessor);
+ checkMethodIsRemoved(classSubject, getterAccessor);
+ checkMethodIsRemoved(classSubject, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getterAccessor);
- checkMethodIsPresent(classSubject, setterAccessor);
+ checkMethodIsKept(classSubject, getterAccessor);
+ checkMethodIsKept(classSubject, setterAccessor);
}
});
}
@@ -400,7 +403,7 @@
"noUseOfPropertyAccessorFromLambda");
runTest("accessors", mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "property";
MemberNaming.MethodSignature getterAccessor =
@@ -408,8 +411,8 @@
MemberNaming.MethodSignature setterAccessor =
testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA);
- checkMethodIsAbsent(classSubject, getterAccessor);
- checkMethodIsAbsent(classSubject, setterAccessor);
+ checkMethodIsRemoved(classSubject, getterAccessor);
+ checkMethodIsRemoved(classSubject, setterAccessor);
});
}
@@ -421,9 +424,9 @@
"usePropertyAccessorFromLambda");
runTest("accessors", mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject classSubject = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "property";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
assertFalse(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getterAccessor =
@@ -432,12 +435,12 @@
testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getterAccessor);
- checkMethodIsAbsent(classSubject, setterAccessor);
+ checkMethodIsRemoved(classSubject, getterAccessor);
+ checkMethodIsRemoved(classSubject, setterAccessor);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getterAccessor);
- checkMethodIsPresent(classSubject, setterAccessor);
+ checkMethodIsKept(classSubject, getterAccessor);
+ checkMethodIsKept(classSubject, setterAccessor);
}
});
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index 29c5582..c8c8aec 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -41,23 +41,23 @@
final String extraRules = keepClassMethod(mainClassName, testMethodSignature);
runTest("dataclass", mainClassName, extraRules, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject dataClass = checkClassExists(dexInspector, TEST_DATA_CLASS.getClassName());
+ ClassSubject dataClass = checkClassIsKept(dexInspector, TEST_DATA_CLASS.getClassName());
// Getters should be removed after inlining, which is possible only if access is relaxed.
final boolean areGetterPresent = !allowAccessModification;
- checkMethod(dataClass, NAME_GETTER_METHOD, areGetterPresent);
- checkMethod(dataClass, AGE_GETTER_METHOD, areGetterPresent);
+ checkMethodisKeptOrRemoved(dataClass, NAME_GETTER_METHOD, areGetterPresent);
+ checkMethodisKeptOrRemoved(dataClass, AGE_GETTER_METHOD, areGetterPresent);
// No use of componentN functions.
- checkMethodIsAbsent(dataClass, COMPONENT1_METHOD);
- checkMethodIsAbsent(dataClass, COMPONENT2_METHOD);
+ checkMethodIsRemoved(dataClass, COMPONENT1_METHOD);
+ checkMethodIsRemoved(dataClass, COMPONENT2_METHOD);
// No use of copy functions.
- checkMethodIsAbsent(dataClass, COPY_METHOD);
- checkMethodIsAbsent(dataClass, COPY_DEFAULT_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
- ClassSubject classSubject = checkClassExists(dexInspector, mainClassName);
- MethodSubject testMethod = checkMethodIsPresent(classSubject, testMethodSignature);
+ ClassSubject classSubject = checkClassIsKept(dexInspector, mainClassName);
+ MethodSubject testMethod = checkMethodIsKept(classSubject, testMethodSignature);
DexCode dexCode = getDexCode(testMethod);
if (allowAccessModification) {
// Both getters should be inlined
@@ -76,24 +76,24 @@
final String extraRules = keepClassMethod(mainClassName, testMethodSignature);
runTest("dataclass", mainClassName, extraRules, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject dataClass = checkClassExists(dexInspector, TEST_DATA_CLASS.getClassName());
+ ClassSubject dataClass = checkClassIsKept(dexInspector, TEST_DATA_CLASS.getClassName());
// ComponentN functions should be removed after inlining, which is possible only if access
// is relaxed.
final boolean areComponentMethodsPresent = !allowAccessModification;
- checkMethod(dataClass, COMPONENT1_METHOD, areComponentMethodsPresent);
- checkMethod(dataClass, COMPONENT2_METHOD, areComponentMethodsPresent);
+ checkMethodisKeptOrRemoved(dataClass, COMPONENT1_METHOD, areComponentMethodsPresent);
+ checkMethodisKeptOrRemoved(dataClass, COMPONENT2_METHOD, areComponentMethodsPresent);
// No use of getter.
- checkMethodIsAbsent(dataClass, NAME_GETTER_METHOD);
- checkMethodIsAbsent(dataClass, AGE_GETTER_METHOD);
+ checkMethodIsRemoved(dataClass, NAME_GETTER_METHOD);
+ checkMethodIsRemoved(dataClass, AGE_GETTER_METHOD);
// No use of copy functions.
- checkMethodIsAbsent(dataClass, COPY_METHOD);
- checkMethodIsAbsent(dataClass, COPY_DEFAULT_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
- ClassSubject classSubject = checkClassExists(dexInspector, mainClassName);
- MethodSubject testMethod = checkMethodIsPresent(classSubject, testMethodSignature);
+ ClassSubject classSubject = checkClassIsKept(dexInspector, mainClassName);
+ MethodSubject testMethod = checkMethodIsKept(classSubject, testMethodSignature);
DexCode dexCode = getDexCode(testMethod);
if (allowAccessModification) {
checkMethodIsNeverInvoked(dexCode, COMPONENT1_METHOD, COMPONENT2_METHOD);
@@ -111,24 +111,24 @@
final String extraRules = keepClassMethod(mainClassName, testMethodSignature);
runTest("dataclass", mainClassName, extraRules, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject dataClass = checkClassExists(dexInspector, TEST_DATA_CLASS.getClassName());
+ ClassSubject dataClass = checkClassIsKept(dexInspector, TEST_DATA_CLASS.getClassName());
boolean component2IsPresent = !allowAccessModification;
- checkMethod(dataClass, COMPONENT2_METHOD, component2IsPresent);
+ checkMethodisKeptOrRemoved(dataClass, COMPONENT2_METHOD, component2IsPresent);
// Function component1 is not used.
- checkMethodIsAbsent(dataClass, COMPONENT1_METHOD);
+ checkMethodIsRemoved(dataClass, COMPONENT1_METHOD);
// No use of getter.
- checkMethodIsAbsent(dataClass, NAME_GETTER_METHOD);
- checkMethodIsAbsent(dataClass, AGE_GETTER_METHOD);
+ checkMethodIsRemoved(dataClass, NAME_GETTER_METHOD);
+ checkMethodIsRemoved(dataClass, AGE_GETTER_METHOD);
// No use of copy functions.
- checkMethodIsAbsent(dataClass, COPY_METHOD);
- checkMethodIsAbsent(dataClass, COPY_DEFAULT_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
- ClassSubject classSubject = checkClassExists(dexInspector, mainClassName);
- MethodSubject testMethod = checkMethodIsPresent(classSubject, testMethodSignature);
+ ClassSubject classSubject = checkClassIsKept(dexInspector, mainClassName);
+ MethodSubject testMethod = checkMethodIsKept(classSubject, testMethodSignature);
DexCode dexCode = getDexCode(testMethod);
if (allowAccessModification) {
checkMethodIsNeverInvoked(dexCode, COMPONENT2_METHOD);
@@ -146,10 +146,10 @@
final String extraRules = keepClassMethod(mainClassName, testMethodSignature);
runTest("dataclass", mainClassName, extraRules, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject dataClass = checkClassExists(dexInspector, TEST_DATA_CLASS.getClassName());
+ ClassSubject dataClass = checkClassIsKept(dexInspector, TEST_DATA_CLASS.getClassName());
- checkMethodIsAbsent(dataClass, COPY_METHOD);
- checkMethodIsAbsent(dataClass, COPY_DEFAULT_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
});
}
@@ -161,9 +161,9 @@
final String extraRules = keepClassMethod(mainClassName, testMethodSignature);
runTest("dataclass", mainClassName, extraRules, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject dataClass = checkClassExists(dexInspector, TEST_DATA_CLASS.getClassName());
+ ClassSubject dataClass = checkClassIsKept(dexInspector, TEST_DATA_CLASS.getClassName());
- checkMethodIsAbsent(dataClass, COPY_DEFAULT_METHOD);
+ checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
});
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
index 8fef44c..021e045 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
@@ -28,7 +28,7 @@
runTest("intrinsics", "intrinsics.IntrinsicsKt", extraRules, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject intrinsicsClass = checkClassExists(
+ ClassSubject intrinsicsClass = checkClassIsKept(
dexInspector, KOTLIN_INTRINSICS_CLASS.getClassName());
checkMethodsPresence(intrinsicsClass,
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index f884376..74e3d5e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.kotlin.TestKotlinClass.KotlinProperty;
import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
import com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -13,6 +14,7 @@
import com.android.tools.r8.utils.DexInspector.ClassSubject;
import com.android.tools.r8.utils.DexInspector.FieldSubject;
import com.android.tools.r8.utils.InternalOptions;
+import java.util.Map.Entry;
import java.util.function.Consumer;
import org.junit.Test;
@@ -89,13 +91,19 @@
"mutableProperty_noUseOfProperties");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
MUTABLE_PROPERTY_CLASS.getClassName());
- for (String propertyName : MUTABLE_PROPERTY_CLASS.properties.keySet()) {
- checkMethodIsAbsent(classSubject,
- MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName));
- checkMethodIsAbsent(classSubject,
- MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName));
+ for (Entry<String, KotlinProperty> property : MUTABLE_PROPERTY_CLASS.properties.entrySet()) {
+ MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(property.getKey());
+ MethodSignature setter = MUTABLE_PROPERTY_CLASS.getSetterForProperty(property.getKey());
+ if (property.getValue().getVisibility() == Visibility.PRIVATE) {
+ // Private properties have no getter/setter
+ checkMethodIsAbsent(classSubject, getter);
+ checkMethodIsAbsent(classSubject, setter);
+ } else {
+ checkMethodIsRemoved(classSubject, getter);
+ checkMethodIsRemoved(classSubject, setter);
+ }
}
});
}
@@ -106,10 +114,10 @@
"mutableProperty_usePrivateProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "privateProp";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
if (!allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
} else {
@@ -128,19 +136,19 @@
"mutableProperty_useProtectedProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "protectedProp";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
// Protected property has private field.
MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getter);
+ checkMethodIsRemoved(classSubject, getter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getter);
+ checkMethodIsKept(classSubject, getter);
}
});
}
@@ -151,19 +159,19 @@
"mutableProperty_useInternalProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "internalProp";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
// Internal property has private field
MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getter);
+ checkMethodIsRemoved(classSubject, getter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getter);
+ checkMethodIsKept(classSubject, getter);
}
});
}
@@ -174,19 +182,19 @@
"mutableProperty_usePublicProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "publicProp";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
// Public property has private field
MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getter);
+ checkMethodIsRemoved(classSubject, getter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getter);
+ checkMethodIsKept(classSubject, getter);
}
});
}
@@ -197,21 +205,21 @@
"mutableProperty_usePrimitiveProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "primitiveProp";
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, "int", propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, "int", propertyName);
MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
MethodSignature setter = MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getter);
- checkMethodIsAbsent(classSubject, setter);
+ checkMethodIsRemoved(classSubject, getter);
+ checkMethodIsRemoved(classSubject, setter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getter);
- checkMethodIsPresent(classSubject, setter);
+ checkMethodIsKept(classSubject, getter);
+ checkMethodIsKept(classSubject, setter);
}
});
}
@@ -222,13 +230,20 @@
"lateInitProperty_noUseOfProperties");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
LATE_INIT_PROPERTY_CLASS.getClassName());
- for (String propertyName : LATE_INIT_PROPERTY_CLASS.properties.keySet()) {
- checkMethodIsAbsent(classSubject,
- LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
- checkMethodIsAbsent(classSubject,
- LATE_INIT_PROPERTY_CLASS.getSetterForProperty(propertyName));
+ for (Entry<String, KotlinProperty> property : LATE_INIT_PROPERTY_CLASS.properties.entrySet()) {
+ MethodSignature getter = LATE_INIT_PROPERTY_CLASS.getGetterForProperty(property.getKey());
+ MethodSignature setter = LATE_INIT_PROPERTY_CLASS.getSetterForProperty(property.getKey());
+ if (property.getValue().getVisibility() == Visibility.PRIVATE) {
+ // Private properties have no getter or setter.
+ checkMethodIsAbsent(classSubject, getter);
+ checkMethodIsAbsent(classSubject, setter);
+
+ } else {
+ checkMethodIsRemoved(classSubject, getter);
+ checkMethodIsRemoved(classSubject, setter);
+ }
}
});
}
@@ -239,7 +254,7 @@
"properties/LateInitPropertyKt", "lateInitProperty_usePrivateLateInitProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
LATE_INIT_PROPERTY_CLASS.getClassName());
String propertyName = "privateLateInitProp";
FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
@@ -262,7 +277,7 @@
"lateInitProperty_useProtectedLateInitProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
LATE_INIT_PROPERTY_CLASS.getClassName());
String propertyName = "protectedLateInitProp";
FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
@@ -272,7 +287,7 @@
}
// Protected late init property have protected getter
- checkMethodIsAbsent(classSubject,
+ checkMethodIsRemoved(classSubject,
LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
});
}
@@ -283,7 +298,7 @@
"properties/LateInitPropertyKt", "lateInitProperty_useInternalLateInitProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
LATE_INIT_PROPERTY_CLASS.getClassName());
String propertyName = "internalLateInitProp";
FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
@@ -291,7 +306,7 @@
assertTrue(fieldSubject.getField().accessFlags.isPublic());
// Internal late init property have protected getter
- checkMethodIsAbsent(classSubject,
+ checkMethodIsRemoved(classSubject,
LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
});
}
@@ -302,7 +317,7 @@
"properties/LateInitPropertyKt", "lateInitProperty_usePublicLateInitProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
LATE_INIT_PROPERTY_CLASS.getClassName());
String propertyName = "publicLateInitProp";
FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
@@ -310,7 +325,7 @@
assertTrue(fieldSubject.getField().accessFlags.isPublic());
// Internal late init property have protected getter
- checkMethodIsAbsent(classSubject,
+ checkMethodIsRemoved(classSubject,
LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
});
}
@@ -321,12 +336,12 @@
"properties/UserDefinedPropertyKt", "userDefinedProperty_noUseOfProperties");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
USER_DEFINED_PROPERTY_CLASS.getClassName());
for (String propertyName : USER_DEFINED_PROPERTY_CLASS.properties.keySet()) {
- checkMethodIsAbsent(classSubject,
+ checkMethodIsRemoved(classSubject,
USER_DEFINED_PROPERTY_CLASS.getGetterForProperty(propertyName));
- checkMethodIsAbsent(classSubject,
+ checkMethodIsRemoved(classSubject,
USER_DEFINED_PROPERTY_CLASS.getSetterForProperty(propertyName));
}
});
@@ -338,22 +353,22 @@
"properties/UserDefinedPropertyKt", "userDefinedProperty_useProperties");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject classSubject = checkClassExists(dexInspector,
+ ClassSubject classSubject = checkClassIsKept(dexInspector,
USER_DEFINED_PROPERTY_CLASS.getClassName());
String propertyName = "durationInSeconds";
// The 'wrapper' property is not assigned to a backing field, it only relies on the wrapped
// property.
checkFieldIsAbsent(classSubject, "int", "durationInSeconds");
- FieldSubject fieldSubject = checkFieldIsPresent(classSubject, "int",
+ FieldSubject fieldSubject = checkFieldIsKept(classSubject, "int",
"durationInMilliSeconds");
MethodSignature getter = USER_DEFINED_PROPERTY_CLASS.getGetterForProperty(propertyName);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(classSubject, getter);
+ checkMethodIsRemoved(classSubject, getter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(classSubject, getter);
+ checkMethodIsKept(classSubject, getter);
}
});
}
@@ -364,12 +379,12 @@
"properties.CompanionPropertiesKt", "companionProperties_usePrimitiveProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector,
+ ClassSubject outerClass = checkClassIsKept(dexInspector,
"properties.CompanionProperties");
- ClassSubject companionClass = checkClassExists(dexInspector,
+ ClassSubject companionClass = checkClassIsKept(dexInspector,
COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "primitiveProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, "int", propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, "int", propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = COMPANION_PROPERTY_CLASS
@@ -379,8 +394,8 @@
// Getter and setter cannot be inlined because we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(companionClass, getter);
- checkMethodIsPresent(companionClass, setter);
+ checkMethodIsKept(companionClass, getter);
+ checkMethodIsKept(companionClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -395,12 +410,12 @@
"properties.CompanionPropertiesKt", "companionProperties_usePrivateProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector,
+ ClassSubject outerClass = checkClassIsKept(dexInspector,
"properties.CompanionProperties");
- ClassSubject companionClass = checkClassExists(dexInspector,
+ ClassSubject companionClass = checkClassIsKept(dexInspector,
COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "privateProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = COMPANION_PROPERTY_CLASS
@@ -413,8 +428,8 @@
// non-null, thus the getter/setter can be inlined if their code is small enough.
// Because the backing field is private, they will call into an accessor (static) method. If
// access relaxation is enabled, this accessor can be removed.
- checkMethodIsAbsent(companionClass, getter);
- checkMethodIsAbsent(companionClass, setter);
+ checkMethodIsRemoved(companionClass, getter);
+ checkMethodIsRemoved(companionClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -429,12 +444,12 @@
"properties.CompanionPropertiesKt", "companionProperties_useInternalProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector,
+ ClassSubject outerClass = checkClassIsKept(dexInspector,
"properties.CompanionProperties");
- ClassSubject companionClass = checkClassExists(dexInspector,
+ ClassSubject companionClass = checkClassIsKept(dexInspector,
COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "internalProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = COMPANION_PROPERTY_CLASS
@@ -444,8 +459,8 @@
// Getter and setter cannot be inlined because we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(companionClass, getter);
- checkMethodIsPresent(companionClass, setter);
+ checkMethodIsKept(companionClass, getter);
+ checkMethodIsKept(companionClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -460,12 +475,12 @@
"properties.CompanionPropertiesKt", "companionProperties_usePublicProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector,
+ ClassSubject outerClass = checkClassIsKept(dexInspector,
"properties.CompanionProperties");
- ClassSubject companionClass = checkClassExists(dexInspector,
+ ClassSubject companionClass = checkClassIsKept(dexInspector,
COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "publicProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = COMPANION_PROPERTY_CLASS
@@ -475,8 +490,8 @@
// Getter and setter cannot be inlined because we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(companionClass, getter);
- checkMethodIsPresent(companionClass, setter);
+ checkMethodIsKept(companionClass, getter);
+ checkMethodIsKept(companionClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -492,10 +507,10 @@
"companionLateInitProperties_usePrivateLateInitProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
- ClassSubject companionClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
+ ClassSubject companionClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "privateLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -506,8 +521,8 @@
// non-null, thus the getter/setter can be inlined if their code is small enough.
// Because the backing field is private, they will call into an accessor (static) method. If
// access relaxation is enabled, this accessor can be removed.
- checkMethodIsAbsent(companionClass, getter);
- checkMethodIsAbsent(companionClass, setter);
+ checkMethodIsRemoved(companionClass, getter);
+ checkMethodIsRemoved(companionClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -523,10 +538,10 @@
"companionLateInitProperties_useInternalLateInitProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
- ClassSubject companionClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
+ ClassSubject companionClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "internalLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -534,8 +549,8 @@
// Getter and setter cannot be inlined because we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(companionClass, getter);
- checkMethodIsPresent(companionClass, setter);
+ checkMethodIsKept(companionClass, getter);
+ checkMethodIsKept(companionClass, setter);
assertTrue(fieldSubject.getField().accessFlags.isPublic());
});
}
@@ -547,10 +562,10 @@
"companionLateInitProperties_usePublicLateInitProp");
runTest(PACKAGE_NAME, mainClass, disableClassInliner, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
- ClassSubject companionClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject outerClass = checkClassIsKept(dexInspector, testedClass.getOuterClassName());
+ ClassSubject companionClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "publicLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -558,8 +573,8 @@
// Getter and setter cannot be inlined because we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(companionClass, getter);
- checkMethodIsPresent(companionClass, setter);
+ checkMethodIsKept(companionClass, getter);
+ checkMethodIsKept(companionClass, setter);
assertTrue(fieldSubject.getField().accessFlags.isPublic());
});
}
@@ -571,9 +586,9 @@
"properties.ObjectPropertiesKt", "objectProperties_usePrimitiveProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "primitiveProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, "int", propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -581,8 +596,8 @@
// Getter and setter cannot be inlined when we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(objectClass, getter);
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsKept(objectClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -598,9 +613,9 @@
"properties.ObjectPropertiesKt", "objectProperties_usePrivateProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "privateProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -625,9 +640,9 @@
"properties.ObjectPropertiesKt", "objectProperties_useInternalProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "internalProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -635,8 +650,8 @@
// Getter and setter cannot be inlined when we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(objectClass, getter);
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsKept(objectClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -652,9 +667,9 @@
"properties.ObjectPropertiesKt", "objectProperties_usePublicProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "publicProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -662,8 +677,8 @@
// Getter and setter cannot be inlined when we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(objectClass, getter);
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsKept(objectClass, setter);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
} else {
@@ -679,9 +694,9 @@
"properties.ObjectPropertiesKt", "objectProperties_useLateInitPrivateProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "privateLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -706,9 +721,9 @@
"properties.ObjectPropertiesKt", "objectProperties_useLateInitInternalProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "internalLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -716,8 +731,8 @@
// Getter and setter cannot be inlined when we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(objectClass, getter);
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsKept(objectClass, setter);
assertTrue(fieldSubject.getField().accessFlags.isPublic());
});
}
@@ -729,9 +744,9 @@
"properties.ObjectPropertiesKt", "objectProperties_useLateInitPublicProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "publicLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -739,8 +754,8 @@
// Getter and setter cannot be inlined when we don't know if null check semantic is
// preserved.
- checkMethodIsPresent(objectClass, getter);
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsKept(objectClass, setter);
assertTrue(fieldSubject.getField().accessFlags.isPublic());
});
}
@@ -752,9 +767,9 @@
"properties.FilePropertiesKt", "fileProperties_usePrimitiveProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "primitiveProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, "int", propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -762,12 +777,12 @@
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(objectClass, getter);
- checkMethodIsAbsent(objectClass, setter);
+ checkMethodIsRemoved(objectClass, getter);
+ checkMethodIsRemoved(objectClass, setter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(objectClass, getter);
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsKept(objectClass, setter);
}
});
}
@@ -779,9 +794,9 @@
"properties.FilePropertiesKt", "fileProperties_usePrivateProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "privateProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -805,9 +820,9 @@
"properties.FilePropertiesKt", "fileProperties_useInternalProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "internalProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
// We expect getter to be inlined when access (of the backing field) is relaxed to public.
@@ -816,10 +831,10 @@
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(objectClass, getter);
+ checkMethodIsRemoved(objectClass, getter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(objectClass, getter);
+ checkMethodIsKept(objectClass, getter);
}
});
}
@@ -831,9 +846,9 @@
"properties.FilePropertiesKt", "fileProperties_usePublicProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "publicProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
// We expect getter to be inlined when access (of the backing field) is relaxed to public.
@@ -843,10 +858,10 @@
if (allowAccessModification) {
assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsAbsent(objectClass, getter);
+ checkMethodIsRemoved(objectClass, getter);
} else {
assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsPresent(objectClass, getter);
+ checkMethodIsKept(objectClass, getter);
}
});
}
@@ -858,9 +873,9 @@
"properties.FilePropertiesKt", "fileProperties_useLateInitPrivateProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject fileClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject fileClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "privateLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(fileClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(fileClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -884,9 +899,9 @@
"properties.FilePropertiesKt", "fileProperties_useLateInitInternalProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "internalLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
assertTrue(fieldSubject.getField().accessFlags.isPublic());
@@ -894,10 +909,10 @@
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
// Field is public and getter is small so we expect to always inline it.
- checkMethodIsAbsent(objectClass, getter);
+ checkMethodIsRemoved(objectClass, getter);
// Setter has null check of new value, thus may not be inlined.
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsKept(objectClass, setter);
});
}
@@ -908,16 +923,16 @@
"properties.FilePropertiesKt", "fileProperties_useLateInitPublicProp");
runTest(PACKAGE_NAME, mainClass, (app) -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+ ClassSubject objectClass = checkClassIsKept(dexInspector, testedClass.getClassName());
String propertyName = "publicLateInitProp";
- FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+ FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
assertTrue(fieldSubject.getField().accessFlags.isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
- checkMethodIsAbsent(objectClass, getter);
- checkMethodIsPresent(objectClass, setter);
+ checkMethodIsRemoved(objectClass, getter);
+ checkMethodIsKept(objectClass, setter);
assertTrue(fieldSubject.getField().accessFlags.isPublic());
});
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index 2b1c33f..5a30cfd 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -36,9 +36,9 @@
final String extraRules = keepAllMembers(mainClassName);
runTest(FOLDER, mainClassName, extraRules, app -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject clazz = checkClassExists(dexInspector, ex1.getClassName());
+ ClassSubject clazz = checkClassIsKept(dexInspector, ex1.getClassName());
- MethodSubject testMethod = checkMethodIsPresent(clazz, testMethodSignature);
+ MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature);
DexCode dexCode = getDexCode(testMethod);
long count = Arrays.stream(dexCode.instructions)
.filter(SimplifyIfNotNullKotlinTest::isIf).count();
@@ -62,9 +62,9 @@
final String extraRules = keepAllMembers(mainClassName);
runTest(FOLDER, mainClassName, extraRules, app -> {
DexInspector dexInspector = new DexInspector(app);
- ClassSubject clazz = checkClassExists(dexInspector, ex2.getClassName());
+ ClassSubject clazz = checkClassIsKept(dexInspector, ex2.getClassName());
- MethodSubject testMethod = checkMethodIsPresent(clazz, testMethodSignature);
+ MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature);
DexCode dexCode = getDexCode(testMethod);
long count = Arrays.stream(dexCode.instructions)
.filter(SimplifyIfNotNullKotlinTest::isIf).count();
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 590baa6..4214a67 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -10,11 +10,12 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.StringResource;
@@ -23,9 +24,7 @@
import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DebugLocalInfo;
@@ -54,9 +53,11 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.shaking.ProguardRuleParserException;
+import com.android.tools.r8.utils.AbortException;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.FoundClassSubject;
@@ -64,6 +65,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.MainDexList;
+import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
@@ -102,6 +104,8 @@
public static TemporaryFolder generatedApplicationsFolder =
ToolHelper.getTemporaryFolderForTest();
+ private List<Diagnostic> errors = new ArrayList<>();
+
// Generate the test applications in a @BeforeClass method, as they are used by several tests.
@BeforeClass
public static void generateTestApplications() throws Throwable {
@@ -179,12 +183,15 @@
try {
verifyMainDexContains(TWO_LARGE_CLASSES, getTwoLargeClassesAppPath(), false);
fail("Expect to fail, for there are too many classes for the main-dex list.");
- } catch (DexOverflowException e) {
+ } catch (AbortException e) {
+ assertEquals(1, errors.size());
+ String message = errors.get(0).getDiagnosticMessage();
// Make sure {@link MonoDexDistributor} was _not_ used.
- assertFalse(e.getMessage().contains("single dex file"));
+ assertFalse(message.contains("single dex file"));
// Make sure what exceeds the limit is the number of methods.
- assertTrue(e.getMessage().contains("# methods: "
- + String.valueOf(TWO_LARGE_CLASSES.size() * MAX_METHOD_COUNT)));
+ assertTrue(
+ message.contains(
+ "# methods: " + String.valueOf(TWO_LARGE_CLASSES.size() * MAX_METHOD_COUNT)));
}
}
@@ -220,12 +227,16 @@
try {
verifyMainDexContains(MANY_CLASSES, getManyClassesMultiDexAppPath(), false);
fail("Expect to fail, for there are too many classes for the main-dex list.");
- } catch (DexOverflowException e) {
+ } catch (AbortException e) {
+ assertEquals(1, errors.size());
+ String message = errors.get(0).getDiagnosticMessage();
// Make sure {@link MonoDexDistributor} was _not_ used.
- assertFalse(e.getMessage().contains("single dex file"));
+ assertFalse(message.contains("single dex file"));
// Make sure what exceeds the limit is the number of methods.
- assertTrue(e.getMessage().contains("# methods: "
- + String.valueOf(MANY_CLASSES_COUNT * MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS)));
+ assertTrue(
+ message.contains(
+ "# methods: "
+ + String.valueOf(MANY_CLASSES_COUNT * MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS)));
}
}
@@ -444,15 +455,22 @@
// Notice that this one fails due to the min API.
try {
generateApplication(
- MANY_CLASSES, AndroidApiLevel.K.getLevel(), false,
- MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS);
+ MANY_CLASSES,
+ AndroidApiLevel.K.getLevel(),
+ false,
+ MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS,
+ new TestDiagnosticsHandler());
fail("Expect to fail, for there are many classes while multidex is not enabled.");
- } catch (DexOverflowException e) {
+ } catch (AbortException e) {
+ assertEquals(1, errors.size());
+ String message = errors.get(0).getDiagnosticMessage();
// Make sure {@link MonoDexDistributor} was used.
- assertTrue(e.getMessage().contains("single dex file"));
+ assertTrue(message.contains("single dex file"));
// Make sure what exceeds the limit is the number of methods.
- assertTrue(e.getMessage().contains("# methods: "
- + String.valueOf(MANY_CLASSES_COUNT * MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS)));
+ assertTrue(
+ message.contains(
+ "# methods: "
+ + String.valueOf(MANY_CLASSES_COUNT * MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS)));
}
}
@@ -498,7 +516,7 @@
private void doVerifyMainDexContains(
List<String> mainDex, Path app, boolean singleDexApp, boolean minimalMainDex,
MultiDexTestMode testMode)
- throws IOException, CompilationException, ExecutionException, ProguardRuleParserException,
+ throws IOException, ExecutionException, ProguardRuleParserException,
CompilationFailedException {
AndroidApp originalApp = AndroidApp.builder().addProgramFiles(app).build();
DexInspector originalInspector = new DexInspector(originalApp);
@@ -508,7 +526,7 @@
}
Path outDir = temp.newFolder().toPath();
R8Command.Builder builder =
- R8Command.builder()
+ R8Command.builder(new TestDiagnosticsHandler())
.addProgramFiles(app)
.setMode(
minimalMainDex && mainDex.size() > 0
@@ -587,15 +605,27 @@
}
public static AndroidApp generateApplication(List<String> classes, int minApi, int methodCount)
- throws IOException, ExecutionException, CompilationException {
+ throws IOException, ExecutionException {
return generateApplication(classes, minApi, false, methodCount);
}
private static AndroidApp generateApplication(
List<String> classes, int minApi, boolean intermediate, int methodCount)
- throws IOException, ExecutionException, CompilationException {
+ throws IOException, ExecutionException {
+ return generateApplication(
+ classes, minApi, intermediate, methodCount, new DefaultDiagnosticsHandler());
+ }
+
+ private static AndroidApp generateApplication(
+ List<String> classes,
+ int minApi,
+ boolean intermediate,
+ int methodCount,
+ DiagnosticsHandler diagnosticsHandler)
+ throws IOException, ExecutionException {
Timing timing = new Timing("MainDexListTests");
- InternalOptions options = new InternalOptions();
+ InternalOptions options =
+ new InternalOptions(new DexItemFactory(), new Reporter(diagnosticsHandler));
options.minApiLevel = minApi;
options.intermediate = intermediate;
DexItemFactory factory = options.itemFactory;
@@ -765,4 +795,12 @@
throw new Unreachable();
}
}
+
+ private class TestDiagnosticsHandler implements DiagnosticsHandler {
+
+ @Override
+ public void error(Diagnostic error) {
+ errors.add(error);
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
index deb90e4..38af4de 100644
--- a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
@@ -9,7 +9,6 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
@@ -270,8 +269,7 @@
}
private R8Command.Builder getCommandForInstrumentation(
- Path out, Path flag, Path mainApp, Path instrApp)
- throws CompilationException, IOException {
+ Path out, Path flag, Path mainApp, Path instrApp) throws IOException {
return R8Command.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar(), mainApp)
.addProgramFiles(instrApp)
@@ -279,9 +277,8 @@
.addProguardConfigurationFiles(flag);
}
- private R8Command.Builder getCommandForApps(
- Path out, Path flag, Path... jars)
- throws CompilationException, IOException {
+ private R8Command.Builder getCommandForApps(Path out, Path flag, Path... jars)
+ throws IOException {
return R8Command.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addProgramFiles(jars)
@@ -290,7 +287,7 @@
}
private static AndroidApp runR8(R8Command command)
- throws ProguardRuleParserException, ExecutionException, CompilationException, IOException {
+ throws ProguardRuleParserException, ExecutionException, IOException {
return ToolHelper.runR8(command, options -> {
// Disable inlining to make this test not depend on inlining decisions.
options.enableInlining = false;
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index b60ede7..d9808c0 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.ClassAndMemberPublicizer;
@@ -65,7 +64,7 @@
}
NamingLens runMinifier(List<Path> configPaths)
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
+ throws IOException, ProguardRuleParserException, ExecutionException {
ProguardConfiguration configuration =
ToolHelper.loadProguardConfiguration(dexItemFactory, configPaths);
InternalOptions options = new InternalOptions(configuration,
diff --git a/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java b/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
index 1a1ae50..008e4ff 100644
--- a/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
+++ b/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
@@ -16,14 +16,12 @@
import com.android.tools.r8.utils.DexInspector.ClassSubject;
import com.google.common.collect.ImmutableList;
import java.util.List;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(VmTestRunner.class)
public class B80083341 extends TestBase {
- @Ignore("b/80083341")
@Test
public void test() throws Exception {
Class mainClass = TestMain.class;
diff --git a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
index dbd4e23..2df0612 100644
--- a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
+++ b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.resource;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.R8Command;
@@ -25,8 +24,7 @@
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@Test
- public void dataResourceTest()
- throws IOException, CompilationFailedException, CompilationException {
+ public void dataResourceTest() throws IOException, CompilationFailedException {
String packageName = "dataresource";
String mainClassName = packageName + ".ResourceTest";
Path inputJar = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR,
diff --git a/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java b/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
index e6c9ada..e0d9ecf 100644
--- a/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
+++ b/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.rewrite.longcompare;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
@@ -35,7 +34,7 @@
public TemporaryFolder tmpOutputDir = ToolHelper.getTemporaryFolderForTest();
void compileWithD8(Path intputPath, Path outputPath)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
D8.run(
D8Command.builder()
.addProgramFiles(intputPath)
diff --git a/src/test/java/com/android/tools/r8/rewrite/longcompare/RequireNonNullRewriteTest.java b/src/test/java/com/android/tools/r8/rewrite/longcompare/RequireNonNullRewriteTest.java
index fe74da9..a50a667 100644
--- a/src/test/java/com/android/tools/r8/rewrite/longcompare/RequireNonNullRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/longcompare/RequireNonNullRewriteTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.rewrite.longcompare;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
@@ -34,7 +33,7 @@
public TemporaryFolder tmpOutputDir = ToolHelper.getTemporaryFolderForTest();
void compileWithD8(Path intputPath, Path outputPath, CompilationMode mode)
- throws IOException, CompilationException, CompilationFailedException {
+ throws IOException, CompilationFailedException {
D8.run(
D8Command.builder()
.setMode(mode)
@@ -68,7 +67,7 @@
}
private void runTest(CompilationMode mode)
- throws IOException, CompilationException, ExecutionException, CompilationFailedException {
+ throws IOException, ExecutionException, CompilationFailedException {
final Path inputPath = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + "/rewrite.jar");
Path outputPath = tmpOutputDir.newFolder().toPath();
diff --git a/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java b/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java
index 831d664..8f00f8d 100644
--- a/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java
@@ -117,7 +117,7 @@
assertThat(javaResult.stdout, containsString(impl2.name));
AndroidApp processedApp = compileWithR8(jasminBuilder.build(), proguardConfig,
- // Disable inlining to avoid the (short) tested method from being inlined then removed.
+ // Disable inlining to avoid the (short) tested method from being inlined and then removed.
internalOptions -> internalOptions.enableInlining = false);
// Run processed (output) program on ART
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index f558ee7..c176ff3 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -149,6 +149,13 @@
parser = new ProguardConfigurationParser(new DexItemFactory(), reporter);
}
+ @Before
+ public void resetAllowPartiallyImplementedOptions() {
+ handler = new KeepingDiagnosticHandler();
+ reporter = new Reporter(handler);
+ parser = new ProguardConfigurationParser(new DexItemFactory(), reporter, false);
+ }
+
@Test
public void parse() throws Exception {
ProguardConfigurationParser parser;
@@ -859,7 +866,7 @@
@Test
public void parseKeepdirectories() throws Exception {
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ new ProguardConfigurationParser(new DexItemFactory(), reporter, false);
parser.parse(Paths.get(KEEPDIRECTORIES));
verifyParserEndsCleanly();
}
@@ -1216,6 +1223,7 @@
@Test
public void parse_adaptresourcexxx_keepdirectories_noArguments1() {
+ resetAllowPartiallyImplementedOptions();
ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
"-adaptresourcefilenames",
"-adaptresourcefilecontents",
@@ -1228,6 +1236,7 @@
@Test
public void parse_adaptresourcexxx_keepdirectories_noArguments2() {
+ resetAllowPartiallyImplementedOptions();
ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
"-keepdirectories",
"-adaptresourcefilenames",
@@ -1240,6 +1249,7 @@
@Test
public void parse_adaptresourcexxx_keepdirectories_noArguments3() {
+ resetAllowPartiallyImplementedOptions();
ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
"-adaptresourcefilecontents",
"-keepdirectories",
@@ -1261,6 +1271,7 @@
@Test
public void parse_adaptresourcexxx_keepdirectories_singleArgument() {
+ resetAllowPartiallyImplementedOptions();
ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
"-adaptresourcefilenames " + FILE_FILTER_SINGLE,
"-adaptresourcefilecontents " + FILE_FILTER_SINGLE,
@@ -1293,6 +1304,7 @@
@Test
public void parse_adaptresourcexxx_keepdirectories_multipleArgument() {
+ resetAllowPartiallyImplementedOptions();
ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
"-adaptresourcefilenames " + FILE_FILTER_MULTIPLE,
"-adaptresourcefilecontents " + FILE_FILTER_MULTIPLE,
@@ -1309,7 +1321,7 @@
"-adaptresourcefilenames", "-adaptresourcefilecontents", "-keepdirectories");
for (String option : options) {
try {
- reset();
+ resetAllowPartiallyImplementedOptions();
parser.parse(createConfigurationForTesting(ImmutableList.of(option + " ,")));
fail("Expect to fail due to the lack of path filter.");
} catch (AbortException e) {
@@ -1324,7 +1336,7 @@
"-adaptresourcefilenames", "-adaptresourcefilecontents", "-keepdirectories");
for (String option : options) {
try {
- reset();
+ resetAllowPartiallyImplementedOptions();
parser.parse(createConfigurationForTesting(ImmutableList.of(option + " xxx,,yyy")));
fail("Expect to fail due to the lack of path filter.");
} catch (AbortException e) {
@@ -1339,7 +1351,7 @@
"-adaptresourcefilenames", "-adaptresourcefilecontents", "-keepdirectories");
for (String option : options) {
try {
- reset();
+ resetAllowPartiallyImplementedOptions();
parser.parse(createConfigurationForTesting(ImmutableList.of(option + " xxx,")));
fail("Expect to fail due to the lack of path filter.");
} catch (AbortException e) {
@@ -1745,6 +1757,24 @@
verifyWithProguard(proguardConfig);
}
+ public void testNotSupported(String option) {
+ try {
+ reset();
+ parser.parse(createConfigurationForTesting(ImmutableList.of(option)));
+ fail("Expect to fail due to unsupported option.");
+ } catch (AbortException e) {
+ checkDiagnostic(handler.errors, null, 1, 1, "Option " + option + " currently not supported");
+ }
+ }
+
+ @Test
+ public void parse_pariallyImplemented_notSupported() {
+ testNotSupported("-keepdirectories");
+ testNotSupported("-adaptresourcefilenames");
+ testNotSupported("-adaptresourcefilecontents");
+ }
+
+
private ProguardConfiguration parseAndVerifyParserEndsCleanly(List<String> config) {
parser.parse(createConfigurationForTesting(config));
verifyParserEndsCleanly();
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/InliningClassVersionTest.java b/src/test/java/com/android/tools/r8/shaking/examples/InliningClassVersionTest.java
new file mode 100644
index 0000000..7fcb318
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/examples/InliningClassVersionTest.java
@@ -0,0 +1,156 @@
+// 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.shaking.examples;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.ArchiveClassFileProvider;
+import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.io.ByteStreams;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+
+public class InliningClassVersionTest extends TestBase {
+
+ private final int OLD_VERSION = Opcodes.V1_6;
+ private final String BASE_DESCRIPTOR = DescriptorUtils.javaTypeToDescriptor(Base.class.getName());
+
+ private static class Base {
+
+ public static void main(String[] args) {
+ System.out.println(Inlinee.foo());
+ }
+ }
+
+ private static class Inlinee {
+ public static String foo() {
+ return "Hello from Inlinee!";
+ }
+ }
+
+ private static class DowngradeVisitor extends ClassVisitor {
+
+ private final int version;
+
+ DowngradeVisitor(ClassVisitor cv, int version) {
+ super(Opcodes.ASM6, cv);
+ this.version = version;
+ }
+
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ assert version > this.version
+ : "Going from " + version + " to " + this.version + " is not a downgrade";
+ super.visit(this.version, access, name, signature, superName, interfaces);
+ }
+ }
+
+ private static byte[] downgradeClass(byte[] classBytes, int version) {
+ ClassWriter writer = new ClassWriter(0);
+ new ClassReader(classBytes).accept(new DowngradeVisitor(writer, version), 0);
+ return writer.toByteArray();
+ }
+
+ @Test
+ public void test() throws Exception {
+ Path inputJar = writeInput();
+ assertEquals(OLD_VERSION, getBaseClassVersion(inputJar));
+ ProcessResult runInput = run(inputJar);
+ assertEquals(0, runInput.exitCode);
+ Path outputJar = runR8(inputJar);
+ ProcessResult runOutput = run(outputJar);
+ assertEquals(runInput.toString(), runOutput.toString());
+ assertNotEquals(
+ "Inliner did not upgrade classfile version", OLD_VERSION, getBaseClassVersion(outputJar));
+ }
+
+ private int getBaseClassVersion(Path jar) throws Exception {
+ return getClassVersion(jar, BASE_DESCRIPTOR);
+ }
+
+ private int getClassVersion(Path jar, String descriptor) throws Exception {
+
+ class ClassVersionReader extends ClassVisitor {
+ private int version = -1;
+
+ private ClassVersionReader() {
+ super(Opcodes.ASM6);
+ }
+
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ assert version != -1;
+ this.version = version;
+ }
+ }
+
+ byte[] bytes =
+ ByteStreams.toByteArray(
+ new ArchiveClassFileProvider(jar).getProgramResource(descriptor).getByteStream());
+ ClassVersionReader reader = new ClassVersionReader();
+ new ClassReader(bytes).accept(reader, 0);
+ assert reader.version != -1;
+ return reader.version;
+ }
+
+ private Path writeInput() throws Exception {
+ Path inputJar = temp.getRoot().toPath().resolve("input.jar");
+ ClassFileConsumer consumer = new ClassFileConsumer.ArchiveConsumer(inputJar);
+ consumer.accept(
+ downgradeClass(ToolHelper.getClassAsBytes(Base.class), OLD_VERSION), BASE_DESCRIPTOR, null);
+ consumer.accept(
+ ToolHelper.getClassAsBytes(Inlinee.class),
+ DescriptorUtils.javaTypeToDescriptor(Inlinee.class.getName()),
+ null);
+ consumer.finished(null);
+ return inputJar;
+ }
+
+ private ProcessResult run(Path jar) throws Exception {
+ return ToolHelper.runJava(jar, Base.class.getName());
+ }
+
+ private Path runR8(Path inputJar) throws Exception {
+ List<String> keepRule =
+ Collections.singletonList(
+ "-keep class " + Base.class.getName() + " { public static void main(...); }");
+ Path outputJar = temp.getRoot().toPath().resolve("output.jar");
+ ToolHelper.runR8(
+ R8Command.builder()
+ .addProgramFiles(inputJar)
+ .addLibraryFiles(Paths.get(ToolHelper.JAVA_8_RUNTIME))
+ .addProguardConfiguration(keepRule, Origin.unknown())
+ .setOutput(outputJar, OutputMode.ClassFile)
+ .build());
+ return outputJar;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingAbstractMethodRemovalTest.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingAbstractMethodRemovalTest.java
new file mode 100644
index 0000000..a5b13a7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingAbstractMethodRemovalTest.java
@@ -0,0 +1,49 @@
+// 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.shaking.examples;
+
+import com.android.tools.r8.TestBase.MinifyMode;
+import com.android.tools.r8.shaking.TreeShakingTest;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+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 TreeShakingAbstractMethodRemovalTest extends TreeShakingTest {
+
+ @Parameters(name = "mode:{0}-{1} minify:{2}")
+ public static Collection<Object[]> data() {
+ List<Object[]> parameters = new ArrayList<>();
+ for (MinifyMode minify : MinifyMode.values()) {
+ parameters.add(new Object[] {Frontend.JAR, Backend.CF, minify});
+ parameters.add(new Object[] {Frontend.JAR, Backend.DEX, minify});
+ parameters.add(new Object[] {Frontend.DEX, Backend.DEX, minify});
+ }
+ return parameters;
+ }
+
+ public TreeShakingAbstractMethodRemovalTest(
+ Frontend frontend, Backend backend, MinifyMode minify) {
+ super(
+ "examples/abstractmethodremoval",
+ "abstractmethodremoval.AbstractMethodRemoval",
+ frontend,
+ backend,
+ minify);
+ }
+
+ @Test
+ public void test() throws Exception {
+ runTest(
+ null,
+ null,
+ null,
+ ImmutableList.of("src/test/examples/abstractmethodremoval/keep-rules.txt"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
index 91fc9d4..642045c 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -110,7 +110,7 @@
// The test contains only a member class so the enclosing-method attribute will be null.
assertEquals(
- !keepAnnotations && forceProguardCompatibility,
+ forceProguardCompatibility,
!clazz.getDexClass().getInnerClasses().isEmpty());
assertEquals(forceProguardCompatibility || keepAnnotations,
clazz.annotation(annotationClass.getCanonicalName()).isPresent());
diff --git a/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java b/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java
index 1fd6afd..3381473 100644
--- a/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java
+++ b/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java
@@ -585,7 +585,7 @@
private void notIntMethodBuilder(SmaliBuilder builder, String name, Object parameters) {
Integer value = (Integer) parameters;
- builder.addStaticMethod("long", name, Collections.emptyList(),
+ builder.addStaticMethod("int", name, Collections.emptyList(),
1,
" const v0, " + value,
" not-int v0, v0",
@@ -950,6 +950,7 @@
addCmpFloatFoldTests(testBuilder);
addCmpDoubleFoldTests(testBuilder);
addCmpLongFold(testBuilder);
+ runDex2Oat(testBuilder.builder.build());
testBuilder.run();
}
diff --git a/src/test/java/com/android/tools/r8/smali/DexMoveInstructionsTest.java b/src/test/java/com/android/tools/r8/smali/DexMoveInstructionsTest.java
new file mode 100644
index 0000000..c92b73b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/smali/DexMoveInstructionsTest.java
@@ -0,0 +1,95 @@
+// 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.smali;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.DescriptorUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+public class DexMoveInstructionsTest extends SmaliTestBase {
+
+ public static final String CLASS = "Test";
+
+ @Test
+ public void testValidObjectMoves() throws Throwable {
+ ProcessResult result = testMoves("ExpectedToPass", "Ljava/lang/String;", Arrays.asList(
+ "move-object",
+ "move-object/from16",
+ "move-object/16"));
+ assertEquals(result.toString(), 0, result.exitCode);
+ }
+
+ @Test
+ public void testInvalidObjectMoves() throws Throwable {
+ ProcessResult result = testMoves("ExpectedToFail", "Ljava/lang/String;", Arrays.asList(
+ "move",
+ "move/from16",
+ "move/16"));
+ assertEquals(result.toString(), 1, result.exitCode);
+ assertTrue("Did not find 'Verification error' in " + result.stderr,
+ result.stderr.contains("Verification error") || result.stderr.contains("VerifyError"));
+ }
+
+ @Test
+ public void testValidSingleMoves() throws Throwable {
+ ProcessResult result = testMoves("ExpectedToPass", "I", Arrays.asList(
+ "move",
+ "move/from16",
+ "move/16"));
+ assertEquals(result.toString(), 0, result.exitCode);
+ }
+
+ @Test
+ public void testInvalidSingleMoves() throws Throwable {
+ ProcessResult result = testMoves("ExpectedToFail", "I", Arrays.asList(
+ "move-object",
+ "move-object/from16",
+ "move-object/16"));
+ assertEquals(result.toString(), 1, result.exitCode);
+ assertTrue("Did not find 'Verification error' in " + result.stderr,
+ result.stderr.contains("Verification error") || result.stderr.contains("VerifyError"));
+ }
+
+ private ProcessResult testMoves(String clazz, String typeDesc, List<String> moveOps)
+ throws Throwable {
+ String typeName = DescriptorUtils.descriptorToJavaType(typeDesc);
+
+ SmaliBuilder builder = new SmaliBuilder(clazz);
+ int i = 0;
+ for (String moveOp : moveOps) {
+ builder.addStaticMethod(typeName, "test" + i++, Collections.singletonList(typeName),
+ 1,
+ " " + moveOp + " v0, p0",
+ typeDesc.startsWith("L") ? "return-object v0" : " return v0"
+ );
+ }
+
+ List<String> main = new ArrayList<>();
+ main.add(" sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;");
+ main.add(" const v2, 0");
+ i = 0;
+ for (String moveOp : moveOps) {
+ main.add(" invoke-static { v2 }, L" + clazz + ";->test" + i++
+ + "(" + typeDesc + ")" + typeDesc);
+ if (typeDesc.startsWith("L")) {
+ main.add(" move-result-object v1");
+ } else {
+ main.add(" move-result v1");
+ }
+ main.add(" invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->print(" + typeDesc + ")V");
+ }
+ main.add(" return-void");
+ builder.addMainMethod(3, main.toArray(new String[0]));
+
+ return runOnArtRaw(builder.build(), clazz);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/smali/IfZeroObjectTest.java b/src/test/java/com/android/tools/r8/smali/IfZeroObjectTest.java
new file mode 100644
index 0000000..ebcd835
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/smali/IfZeroObjectTest.java
@@ -0,0 +1,68 @@
+// 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.smali;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+public class IfZeroObjectTest extends SmaliTestBase {
+
+ public static final String CLASS = "Test";
+
+ @Test
+ public void testObjectIfs() throws Throwable {
+ ProcessResult result = testIfs("ExpectedToPass", Arrays.asList(
+ "eqz",
+ "nez"));
+ assertEquals(result.toString(), 0, result.exitCode);
+ }
+
+ @Test
+ public void testNumericIfs() throws Throwable {
+ ProcessResult result = testIfs("ExpectedToFail", Arrays.asList(
+ "ltz",
+ "gez",
+ "gtz",
+ "lez"));
+ assertEquals(result.toString(), 1, result.exitCode);
+ assertTrue("Did not find 'Verification error' in " + result.stderr,
+ result.stderr.contains("Verification error") || result.stderr.contains("VerifyError"));
+ }
+
+ private ProcessResult testIfs(String clazz, List<String> ifZeroOps) throws Throwable {
+
+ SmaliBuilder builder = new SmaliBuilder(clazz);
+ for (String ifZeroOp : ifZeroOps) {
+ builder.addStaticMethod("int", "if" + ifZeroOp, Collections.singletonList("java.lang.Object"),
+ 1,
+ " if-" + ifZeroOp + " p0, :L",
+ " const v0, 0",
+ " return v0",
+ " :L",
+ " const v0, 1",
+ " return v0"
+ );
+ }
+
+ List<String> main = new ArrayList<>();
+ main.add(" sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;");
+ for (String ifZeroOp : ifZeroOps) {
+ main.add(" invoke-static { p0 }, L" + clazz + ";->if" + ifZeroOp + "(Ljava/lang/Object;)I");
+ main.add(" move-result v1");
+ main.add(" invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->print(I)V");
+ }
+ main.add(" return-void");
+ builder.addMainMethod(2, main.toArray(new String[0]));
+
+ return runOnArtRaw(builder.build(), clazz);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index eb66c51..371c4d1 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -94,7 +94,7 @@
DEFAULT_METHOD_NAME,
parameters,
2,
- " move v0, p0",
+ " move-object v0, p0",
" const-string v1, \"Test\"",
" invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
" move-result-object v0",
@@ -158,7 +158,7 @@
DEFAULT_METHOD_NAME,
parameters,
2,
- " move v0, p0",
+ " move-object v0, p0",
" const-string v1, \"Test1\"",
" invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
" move-result-object v0",
@@ -231,7 +231,7 @@
DEFAULT_METHOD_NAME,
parameters,
2,
- " move v0, p0",
+ " move-object v0, p0",
" const-string v1, \"Test\"",
" invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
" move-result-object v0",
@@ -354,7 +354,7 @@
DEFAULT_METHOD_NAME,
parameters,
3,
- " move v0, p0",
+ " move-object v0, p0",
" const-wide v1, 0x7fffffff00000000L",
" invoke-virtual { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;",
" move-result-object v0",
@@ -430,7 +430,7 @@
DEFAULT_METHOD_NAME,
parameters,
3,
- " move v0, p0",
+ " move-object v0, p0",
" const-wide v1, 0x3ff0000000000000L",
" invoke-virtual { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(D)Ljava/lang/StringBuilder;",
" move-result-object v0",
@@ -793,7 +793,7 @@
"method1",
parameters,
2,
- " move v0, p0",
+ " move-object v0, p0",
" const-string v1, \"Test\"",
" invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
" move-result-object v0",
@@ -809,7 +809,7 @@
"method2",
parameters,
2,
- " move v0, p0",
+ " move-object v0, p0",
" const-string v1, \"Test\"",
" invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
" move-result-object v0",
@@ -878,7 +878,7 @@
DEFAULT_METHOD_NAME,
parameters,
2,
- " move v0, p0",
+ " move-object v0, p0",
" const-string v1, \"Test\"",
" invoke-virtual { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
" move-result-object v0",
diff --git a/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java b/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
index dae717e..5270cd4 100644
--- a/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
@@ -6,12 +6,16 @@
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
import org.junit.Test;
public class RemoveWriteOfUnusedFieldsTest extends SmaliTestBase {
@@ -33,20 +37,28 @@
builder.addStaticField("stringField", "Ljava/lang/String;");
builder.addStaticField("testField", "LTest;");
+ boolean isDalvik = ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST);
+ String additionalConstZero = isDalvik ? "const v0, 0" : "";
+ String additionalConstZeroWide = isDalvik ? "const-wide v0, 0" : "";
+
builder.addStaticMethod("void", "test", ImmutableList.of(),
2,
"const v0, 0",
- "sput-byte v0, LTest;->booleanField:Z",
+ "sput-boolean v0, LTest;->booleanField:Z",
"sput-byte v0, LTest;->byteField:B",
"sput-short v0, LTest;->shortField:S",
"sput v0, LTest;->intField:I",
+ // Dalvik 4.x. does not require a new const 0 here.
"sput v0, LTest;->floatField:F",
+ additionalConstZero, // Required for Dalvik 4.x.
"sput-char v0, LTest;->charField:C",
+ "const v0, 0",
"sput-object v0, LTest;->objectField:Ljava/lang/Object;",
"sput-object v0, LTest;->stringField:Ljava/lang/String;",
"sput-object v0, LTest;->testField:LTest;",
"const-wide v0, 0",
"sput-wide v0, LTest;->longField:J",
+ additionalConstZeroWide, // Required for Dalvik 4.x.
"sput-wide v0, LTest;->doubleField:D",
"return-void");
@@ -55,9 +67,16 @@
" invoke-static { }, LTest;->test()V",
" return-void ");
+ AndroidApp input =
+ AndroidApp.builder().addDexProgramData(builder.compile(), Origin.unknown()).build();
+
+ Path inputPath = temp.getRoot().toPath().resolve("input.zip");
+ input.writeToZip(inputPath, OutputMode.DexIndexed);
+ ToolHelper.runArtNoVerificationErrors(inputPath.toString(), DEFAULT_CLASS_NAME);
+
AndroidApp app =
compileWithR8(
- AndroidApp.builder().addDexProgramData(builder.compile(), Origin.unknown()).build(),
+ input,
keepMainProguardConfiguration("Test"),
options -> options.enableInlining = false);
@@ -84,32 +103,53 @@
builder.addInstanceField("stringField", "Ljava/lang/String;");
builder.addInstanceField("testField", "LTest;");
+ boolean isDalvik = ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST);
+ String additionalConstZero = isDalvik ? "const v0, 0" : "";
+ String additionalConstZeroWide = isDalvik ? "const-wide v0, 0" : "";
+
builder.addInstanceMethod("void", "test", ImmutableList.of(),
2,
"const v0, 0",
- "iput-byte v0, p0, LTest;->booleanField:Z",
+ "iput-boolean v0, p0, LTest;->booleanField:Z",
"iput-byte v0, p0, LTest;->byteField:B",
"iput-short v0, p0, LTest;->shortField:S",
"iput v0, p0, LTest;->intField:I",
+ // Dalvik 4.x. does not require a new const 0 here.
"iput v0, p0, LTest;->floatField:F",
+ additionalConstZero, // Required for Dalvik 4.x.
"iput-char v0, p0, LTest;->charField:C",
+ "const v0, 0",
"iput-object v0, p0, LTest;->objectField:Ljava/lang/Object;",
"iput-object v0, p0, LTest;->stringField:Ljava/lang/String;",
"iput-object v0, p0, LTest;->testField:LTest;",
"const-wide v0, 0",
"iput-wide v0, p0, LTest;->longField:J",
+ additionalConstZeroWide, // Required for Dalvik 4.x.
"iput-wide v0, p0, LTest;->doubleField:D",
"return-void");
+ builder.addInitializer(ImmutableList.of(), 0,
+ "invoke-direct {p0}, Ljava/lang/Object;-><init>()V",
+ "return-void"
+ );
+
builder.addMainMethod(
1,
" new-instance v0, LTest;",
+ " invoke-direct { v0 }, LTest;-><init>()V",
" invoke-virtual { v0 }, LTest;->test()V",
" return-void ");
+ AndroidApp input =
+ AndroidApp.builder().addDexProgramData(builder.compile(), Origin.unknown()).build();
+
+ Path inputPath = temp.getRoot().toPath().resolve("input.zip");
+ input.writeToZip(inputPath, OutputMode.DexIndexed);
+ ToolHelper.runArtNoVerificationErrors(inputPath.toString(), DEFAULT_CLASS_NAME);
+
AndroidApp app =
compileWithR8(
- AndroidApp.builder().addDexProgramData(builder.compile(), Origin.unknown()).build(),
+ input,
keepMainProguardConfiguration("Test"),
options -> options.enableInlining = false);
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java b/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java
index 2f6eb51..9a6e778 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliBuilder.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.smali;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -334,13 +333,11 @@
return result;
}
- public byte[] compile()
- throws IOException, RecognitionException, DexOverflowException, ExecutionException {
+ public byte[] compile() throws IOException, RecognitionException, ExecutionException {
return Smali.compile(buildSource());
}
- public AndroidApp build()
- throws IOException, RecognitionException, DexOverflowException, ExecutionException {
+ public AndroidApp build() throws IOException, RecognitionException, ExecutionException {
return AndroidApp.builder().addDexProgramData(compile(), Origin.unknown()).build();
}
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java b/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java
index a380834..2297ebd 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java
@@ -6,7 +6,6 @@
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.SmaliWriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
@@ -27,7 +26,7 @@
AndroidApp application =
AndroidApp.builder().addDexProgramData(Smali.compile(smali), Origin.unknown()).build();
assertEquals(smali, SmaliWriter.smali(application, new InternalOptions()));
- } catch (IOException | RecognitionException | ExecutionException | DexOverflowException e) {
+ } catch (IOException | RecognitionException | ExecutionException e) {
throw new RuntimeException(e);
}
}
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
index 3c101ad..6c4b884 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -6,7 +6,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.OutputMode;
@@ -15,7 +14,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
@@ -46,7 +44,7 @@
protected AndroidApp buildApplication(SmaliBuilder builder) {
try {
return AndroidApp.builder().addDexProgramData(builder.compile(), Origin.unknown()).build();
- } catch (IOException | RecognitionException | DexOverflowException | ExecutionException e) {
+ } catch (IOException | RecognitionException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@@ -57,7 +55,7 @@
.addDexProgramData(builder.compile(), EmbeddedOrigin.INSTANCE)
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.build();
- } catch (IOException | RecognitionException | ExecutionException | DexOverflowException e) {
+ } catch (IOException | RecognitionException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@@ -79,7 +77,7 @@
Consumer<InternalOptions> optionsConsumer) {
try {
return ToolHelper.runR8(application, optionsConsumer);
- } catch (IOException | CompilationException e) {
+ } catch (IOException e) {
throw new RuntimeException(e);
}
}
@@ -105,7 +103,9 @@
.addDexProgramData(builder.compile(), EmbeddedOrigin.INSTANCE);
ToolHelper.runR8WithFullResult(command.build(), optionsConsumer);
return dexOutputDir.resolve("classes.dex");
- } catch (CompilationException | IOException | RecognitionException | ExecutionException
+ } catch (IOException
+ | RecognitionException
+ | ExecutionException
| CompilationFailedException e) {
throw new RuntimeException(e);
}
@@ -232,13 +232,11 @@
processdApplication, DEFAULT_CLASS_NAME, returnType, DEFAULT_METHOD_NAME, parameters);
}
- public String runArt(AndroidApp application) throws DexOverflowException {
+ public String runArt(AndroidApp application) {
return runArt(application, DEFAULT_MAIN_CLASS_NAME);
}
-
- public String runArt(AndroidApp application, String mainClass)
- throws DexOverflowException {
+ public String runArt(AndroidApp application, String mainClass) {
try {
Path out = temp.getRoot().toPath().resolve("run-art-input.zip");
// TODO(sgjesse): Pass in a unique temp directory for each run.
@@ -257,8 +255,7 @@
}
}
- public void runDex2Oat(AndroidApp application)
- throws DexOverflowException {
+ public void runDex2Oat(AndroidApp application) {
try {
Path dexOut = temp.getRoot().toPath().resolve("run-dex2oat-input.zip");
Path oatFile = temp.getRoot().toPath().resolve("oat-file");
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 30aa7ef..68de752 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.ApplicationWriter;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
@@ -37,27 +36,27 @@
public class Smali {
public static byte[] compile(String smaliText)
- throws RecognitionException, IOException, DexOverflowException, ExecutionException {
+ throws RecognitionException, IOException, ExecutionException {
return compile(smaliText, 15);
}
public static byte[] compile(String... smaliText)
- throws RecognitionException, IOException, DexOverflowException, ExecutionException {
+ throws RecognitionException, IOException, ExecutionException {
return compile(Arrays.asList(smaliText), 15);
}
public static byte[] compile(String smaliText, int apiLevel)
- throws IOException, RecognitionException, DexOverflowException, ExecutionException {
+ throws IOException, RecognitionException, ExecutionException {
return compile(ImmutableList.of(smaliText), apiLevel);
}
public static byte[] compile(List<String> smaliTexts)
- throws RecognitionException, IOException, DexOverflowException, ExecutionException {
+ throws RecognitionException, IOException, ExecutionException {
return compile(smaliTexts, 15);
}
public static byte[] compile(List<String> smaliTexts, int apiLevel)
- throws RecognitionException, IOException, ExecutionException, DexOverflowException {
+ throws RecognitionException, IOException, ExecutionException {
DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(apiLevel));
for (String smaliText : smaliTexts) {
diff --git a/tests/d8_api_usage_sample.jar b/tests/d8_api_usage_sample.jar
index eb6f10f..f901b9d 100644
--- a/tests/d8_api_usage_sample.jar
+++ b/tests/d8_api_usage_sample.jar
Binary files differ
diff --git a/tests/r8_api_usage_sample.jar b/tests/r8_api_usage_sample.jar
index d838141..f901b9d 100644
--- a/tests/r8_api_usage_sample.jar
+++ b/tests/r8_api_usage_sample.jar
Binary files differ
diff --git a/tools/minify_tool.py b/tools/minify_tool.py
index 08b2ada..787c1e1 100755
--- a/tools/minify_tool.py
+++ b/tools/minify_tool.py
@@ -9,6 +9,9 @@
Given an input JAR (default: r8.jar) and a main-class, generates a new input JAR
with the given main-class in the manifest along with a -keep rule for keeping
just the main entrypoint, and runs R8 in release+classfile mode on the JAR.
+
+If --benchmark-name NAME is given, prints "<NAME>(RunTimeRaw): <elapsed> ms"
+to standard output at the end of the run.
'''
import argparse
@@ -44,8 +47,8 @@
'-O', '--no-debug', dest='debug', action='store_false',
help='Disable assertions when running R8')
parser.add_argument(
- '--print-runtimeraw', metavar='BENCHMARKNAME',
- help='Print "<BENCHMARKNAME>(RunTimeRaw): <elapsed> ms" at the end')
+ '--benchmark-name',
+ help='Print benchmarks with the given name')
def generate_output_name(input_jar, mainclass):
if not mainclass:
@@ -83,7 +86,7 @@
return mo.group(1)
def minify_tool(mainclass=None, input_jar=utils.R8_JAR, output_jar=None, lib=RT,
- debug=True, build=True, print_runtimeraw=None):
+ debug=True, build=True, benchmark_name=None):
if output_jar is None:
output_jar = generate_output_name(input_jar, mainclass)
with utils.TempDir() as path:
@@ -104,9 +107,9 @@
tmp_input_path)
start_time = time.time()
return_code = toolhelper.run('r8', args, debug=debug, build=build)
- if print_runtimeraw:
+ if benchmark_name:
elapsed_ms = 1000 * (time.time() - start_time)
- print('%s-Total(RunTimeRaw): %s ms' % (print_runtimeraw, elapsed_ms))
+ print('%s(RunTimeRaw): %s ms' % (benchmark_name, elapsed_ms))
return return_code
if __name__ == '__main__':
diff --git a/tools/run_bootstrap_benchmark.py b/tools/run_bootstrap_benchmark.py
index 0c608f9..2ae97b2 100755
--- a/tools/run_bootstrap_benchmark.py
+++ b/tools/run_bootstrap_benchmark.py
@@ -14,8 +14,8 @@
parser = argparse.ArgumentParser()
parser.add_argument(
- '--print-runtimeraw', metavar='BENCHMARKNAME',
- help='Print "<BENCHMARKNAME>(RunTimeRaw): <elapsed> ms" at the end')
+ '--name', metavar='NAME', dest='benchmark_name',
+ help='Print "<NAME>(RunTimeRaw): <elapsed> ms" at the end')
if __name__ == '__main__':