Merge "Fix issue where const instructions for uninitialized locals can interfere with arguments."
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 0c0ac08..b992f65 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -118,7 +118,7 @@
}
/** Command-line entry to D8. */
- public static void main(String[] args) throws IOException {
+ public static void main(String[] args) {
if (args.length == 0) {
System.err.println(USAGE_MESSAGE);
System.exit(STATUS_ERROR);
@@ -210,7 +210,7 @@
private static DexApplication optimize(
DexApplication application, AppInfo appInfo, InternalOptions options,
Timing timing, ExecutorService executor)
- throws IOException, ExecutionException {
+ throws IOException, ExecutionException, ApiLevelException {
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
IRConverter converter = new IRConverter(timing, application, appInfo, options, printer);
diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java
index 3827cae..4e4a19b 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.dex.DexFileReader;
import com.android.tools.r8.dex.Segment;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OutputMode;
@@ -16,7 +15,6 @@
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.ExecutionException;
public class DexSegments {
private static class Command extends BaseCommand {
@@ -99,7 +97,7 @@
}
public static void main(String[] args)
- throws IOException, ProguardRuleParserException, CompilationException, ExecutionException {
+ throws IOException, CompilationException {
Command.Builder builder = Command.parse(args);
Command command = builder.build();
if (command.isPrintHelp()) {
diff --git a/src/main/java/com/android/tools/r8/Disassemble.java b/src/main/java/com/android/tools/r8/Disassemble.java
index 2f1d523..a7bfdc9 100644
--- a/src/main/java/com/android/tools/r8/Disassemble.java
+++ b/src/main/java/com/android/tools/r8/Disassemble.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OutputMode;
@@ -133,7 +132,7 @@
}
public static void main(String[] args)
- throws IOException, ProguardRuleParserException, CompilationException, ExecutionException {
+ throws IOException, CompilationException, ExecutionException {
DisassembleCommand.Builder builder = DisassembleCommand.parse(args);
DisassembleCommand command = builder.build();
if (command.isPrintHelp()) {
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index c1234b8..0db183f 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OutputMode;
@@ -100,7 +99,7 @@
}
public static void main(String[] args)
- throws IOException, ProguardRuleParserException, CompilationException, ExecutionException {
+ throws IOException, CompilationException, ExecutionException {
ExtractMarker.Command.Builder builder = ExtractMarker.Command.parse(args);
ExtractMarker.Command command = builder.build();
if (command.isPrintHelp()) {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index b7afda7..a85f397 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -114,12 +114,12 @@
DexApplication application,
AppInfoWithSubtyping appInfo,
InternalOptions options)
- throws ProguardRuleParserException, ExecutionException, IOException {
+ throws ApiLevelException, ExecutionException, IOException {
return new R8(options).optimize(application, appInfo);
}
private DexApplication optimize(DexApplication application, AppInfoWithSubtyping appInfo)
- throws IOException, ProguardRuleParserException, ExecutionException {
+ throws IOException, ApiLevelException, ExecutionException {
return optimize(application, appInfo, GraphLense.getIdentityLense(),
Executors.newSingleThreadExecutor());
}
@@ -129,7 +129,7 @@
AppInfoWithSubtyping appInfo,
GraphLense graphLense,
ExecutorService executorService)
- throws IOException, ProguardRuleParserException, ExecutionException {
+ throws IOException, ApiLevelException, ExecutionException {
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
timing.begin("Create IR");
@@ -207,7 +207,7 @@
}
static CompilationResult runForTesting(AndroidApp app, InternalOptions options)
- throws ProguardRuleParserException, IOException, CompilationException {
+ throws IOException, CompilationException {
ExecutorService executor = ThreadUtils.getExecutorService(options);
try {
return runForTesting(app, options, executor);
@@ -220,12 +220,12 @@
AndroidApp app,
InternalOptions options,
ExecutorService executor)
- throws ProguardRuleParserException, IOException, CompilationException {
+ throws IOException, CompilationException {
return new R8(options).run(app, executor);
}
private CompilationResult run(AndroidApp inputApp, ExecutorService executorService)
- throws IOException, ProguardRuleParserException, CompilationException {
+ throws IOException, CompilationException {
if (options.quiet) {
System.setOut(new PrintStream(ByteStreams.nullOutputStream()));
}
@@ -445,7 +445,7 @@
* @return the compilation result.
*/
public static AndroidApp run(R8Command command)
- throws IOException, CompilationException, ProguardRuleParserException {
+ throws IOException, CompilationException {
ExecutorService executorService = ThreadUtils.getExecutorService(command.getInternalOptions());
try {
return run(command, executorService);
@@ -516,7 +516,7 @@
* @return the compilation result.
*/
public static AndroidApp run(R8Command command, ExecutorService executor)
- throws IOException, CompilationException, ProguardRuleParserException {
+ throws IOException, CompilationException {
InternalOptions options = command.getInternalOptions();
AndroidApp outputApp =
runForTesting(command.getInputApp(), options, executor).androidApp;
diff --git a/src/main/java/com/android/tools/r8/bisect/BisectOptions.java b/src/main/java/com/android/tools/r8/bisect/BisectOptions.java
index d0051dc..8bd2c90 100644
--- a/src/main/java/com/android/tools/r8/bisect/BisectOptions.java
+++ b/src/main/java/com/android/tools/r8/bisect/BisectOptions.java
@@ -121,8 +121,7 @@
return new BisectOptions(goodBuild, badBuild, stateFile, command, output, result);
}
- private static <T> T require(OptionSet options, OptionSpec<T> option, String flag)
- throws IOException {
+ private static <T> T require(OptionSet options, OptionSpec<T> option, String flag) {
T value = options.valueOf(option);
if (value != null) {
return value;
@@ -130,7 +129,7 @@
throw new CompilationError("Missing required option: --" + flag);
}
- private static File exists(String path, String flag) throws IOException {
+ private static File exists(String path, String flag) {
File file = new File(path);
if (file.exists()) {
return file;
@@ -138,7 +137,7 @@
throw new CompilationError("File --" + flag + ": " + file + " does not exist");
}
- private static File directoryExists(String path, String flag) throws IOException {
+ private static File directoryExists(String path, String flag) {
File file = new File(path);
if (file.exists() && file.isDirectory()) {
return file;
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 085b6fa..21402a8 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArray.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
@@ -3,6 +3,7 @@
// 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;
@@ -38,7 +39,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 25a941f..cb2bd6f 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
@@ -3,6 +3,7 @@
// 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;
@@ -38,7 +39,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 a87217b..504b605 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -3,6 +3,7 @@
// 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;
@@ -179,7 +180,7 @@
return NO_TARGETS;
}
- public abstract void buildIR(IRBuilder builder);
+ public abstract void buildIR(IRBuilder builder) throws ApiLevelException;
public DexCallSite getCallSite() {
return null;
@@ -227,6 +228,7 @@
throw new InternalCompilerError("Instruction " + payloadUser + " is not a payload user");
}
+ @Override
public String toString() {
return toString(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 58fb8c1..e52b1ed 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeDirect.java
@@ -3,6 +3,7 @@
// 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;
@@ -47,7 +48,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 742546d..f7f0c93 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
@@ -3,6 +3,7 @@
// 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;
@@ -45,7 +46,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 512f6bc..e8cff27 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeInterface.java
@@ -3,6 +3,7 @@
// 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;
@@ -47,7 +48,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 06eb69e..b40e177 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
@@ -3,6 +3,7 @@
// 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;
@@ -46,7 +47,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 d5ecd11..891dcca 100644
--- a/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java
@@ -3,6 +3,7 @@
// 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;
@@ -29,7 +30,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 e6a16f5..4068d80 100644
--- a/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java
@@ -3,6 +3,7 @@
// 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;
@@ -48,7 +49,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 8fbf95c..27c3255 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeStatic.java
@@ -3,6 +3,7 @@
// 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;
@@ -46,7 +47,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 92a4047..69394b3 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
@@ -3,6 +3,7 @@
// 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;
@@ -46,7 +47,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 7a6e32a..0382872 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeSuper.java
@@ -3,6 +3,7 @@
// 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;
@@ -47,7 +48,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 9ee05b7..e12bccb 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
@@ -3,6 +3,7 @@
// 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;
@@ -46,7 +47,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 1fbf9d9..4de66f6 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
@@ -3,6 +3,7 @@
// 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;
@@ -46,7 +47,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
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 c5c8249..fbacf0b 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
@@ -3,6 +3,7 @@
// 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;
@@ -46,7 +47,7 @@
}
@Override
- public void buildIR(IRBuilder builder) {
+ public void buildIR(IRBuilder builder) throws ApiLevelException {
builder.addInvokeRange(Type.VIRTUAL, getMethod(), getProto(), AA, CCCC);
}
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 9bcf510..0c33273 100644
--- a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
+++ b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
@@ -250,7 +250,7 @@
}
}
- private DxCompatOptions(OptionSet options, Spec spec) throws DxParseError {
+ private DxCompatOptions(OptionSet options, Spec spec) {
help = options.has(spec.help);
debug = options.has(spec.debug);
verbose = options.has(spec.verbose);
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index cca3520..a07a4a3 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -35,7 +35,6 @@
import com.android.tools.r8.utils.MainDexList;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.io.Closer;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -130,8 +129,7 @@
}
private void readProguardMap(DexApplication.Builder builder, ExecutorService executorService,
- List<Future<?>> futures)
- throws IOException {
+ List<Future<?>> futures) {
// Read the Proguard mapping file in parallel with DexCode and DexProgramClass items.
if (inputApp.hasProguardMap()) {
futures.add(executorService.submit(() -> {
@@ -145,8 +143,7 @@
}
private void readMainDexList(DexApplication.Builder builder, ExecutorService executorService,
- List<Future<?>> futures)
- throws IOException {
+ List<Future<?>> futures) {
if (inputApp.hasMainDexList()) {
futures.add(executorService.submit(() -> {
for (Resource resource : inputApp.getMainDexListResources()) {
@@ -184,7 +181,7 @@
}
private <T extends DexClass> void readDexSources(List<Resource> dexSources,
- ClassKind classKind, Queue<T> classes) throws IOException, ExecutionException {
+ ClassKind classKind, Queue<T> classes) throws IOException {
if (dexSources.size() > 0) {
List<DexFileReader> fileReaders = new ArrayList<>(dexSources.size());
int computedMinApiLevel = options.minApiLevel;
@@ -211,7 +208,7 @@
}
private <T extends DexClass> void readClassSources(List<Resource> classSources,
- ClassKind classKind, Queue<T> classes) throws IOException, ExecutionException {
+ ClassKind classKind, Queue<T> classes) {
JarClassFileReader reader = new JarClassFileReader(
application, classKind.bridgeConsumer(classes::add));
// Read classes in parallel.
@@ -227,7 +224,7 @@
}
}
- void readSources() throws IOException, ExecutionException {
+ void readSources() throws IOException {
readDexSources(inputApp.getDexProgramResources(), PROGRAM, programClasses);
readClassSources(inputApp.getClassProgramResources(), PROGRAM, programClasses);
}
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 412b291..0d59d98 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -4,9 +4,6 @@
package com.android.tools.r8.dex;
import com.android.tools.r8.ApiLevelException;
-import com.android.tools.r8.dex.VirtualFile.FilePerClassDistributor;
-import com.android.tools.r8.dex.VirtualFile.FillFilesDistributor;
-import com.android.tools.r8.dex.VirtualFile.PackageMapDistributor;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexAnnotation;
@@ -243,7 +240,7 @@
.replace('.', '/') + ".class";
}
- private byte[] writeMainDexList() throws IOException {
+ private byte[] writeMainDexList() {
if (application.mainDexList.isEmpty()) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexFileReader.java b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
index 09b3c33..7bf5e8c 100644
--- a/src/main/java/com/android/tools/r8/dex/DexFileReader.java
+++ b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
@@ -81,7 +81,7 @@
return parseMapFrom(new DexFile(stream));
}
- private static Segment[] parseMapFrom(DexFile dex) throws IOException {
+ private static Segment[] parseMapFrom(DexFile dex) {
DexFileReader reader = new DexFileReader(dex, ClassKind.PROGRAM, new DexItemFactory());
return reader.segments;
}
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 d47c57d..f4fa365 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -49,6 +49,7 @@
import com.android.tools.r8.naming.NamingLens;
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;
@@ -365,21 +366,13 @@
}
private <T extends DexItem> void writeFixedSectionItems(T[] items, int offset,
- ItemWriter<T> writer) throws ApiLevelException {
+ ThrowingConsumer<T, ApiLevelException> writer) throws ApiLevelException {
assert dest.position() == offset;
for (T item : items) {
writer.accept(item);
}
}
- /**
- * Similar to a {@link Consumer} but throws an {@link ApiLevelException}.
- */
- @FunctionalInterface
- private interface ItemWriter<T> {
- void accept(T t) throws ApiLevelException;
- }
-
private <T extends DexItem> void writeItems(Collection<T> items, Consumer<Integer> offsetSetter,
Consumer<T> writer) {
writeItems(items, offsetSetter, writer, 1);
@@ -452,10 +445,10 @@
private void writeFieldItem(DexField field) {
int classIdx = mapping.getOffsetFor(field.clazz);
- assert (short) classIdx == classIdx;
+ assert (classIdx & 0xFFFF) == classIdx;
dest.putShort((short) classIdx);
int typeIdx = mapping.getOffsetFor(field.type);
- assert (short) typeIdx == typeIdx;
+ assert (typeIdx & 0xFFFF) == typeIdx;
dest.putShort((short) typeIdx);
DexString name = namingLens.lookupName(field);
dest.putInt(mapping.getOffsetFor(name));
@@ -463,10 +456,10 @@
private void writeMethodItem(DexMethod method) {
int classIdx = mapping.getOffsetFor(method.holder);
- assert (short) classIdx == classIdx;
+ assert (classIdx & 0xFFFF) == classIdx;
dest.putShort((short) classIdx);
int protoIdx = mapping.getOffsetFor(method.proto);
- assert (short) protoIdx == protoIdx;
+ assert (protoIdx & 0xFFFF) == protoIdx;
dest.putShort((short) protoIdx);
DexString name = namingLens.lookupName(method);
dest.putInt(mapping.getOffsetFor(name));
@@ -701,7 +694,7 @@
assert methodHandle.isFieldHandle();
fieldOrMethodIdx = mapping.getOffsetFor(methodHandle.asField());
}
- assert (short) fieldOrMethodIdx == fieldOrMethodIdx;
+ assert (fieldOrMethodIdx & 0xFFFF) == fieldOrMethodIdx;
dest.putShort((short) fieldOrMethodIdx);
dest.putShort((short) 0); // unused
}
diff --git a/src/main/java/com/android/tools/r8/dex/Segment.java b/src/main/java/com/android/tools/r8/dex/Segment.java
index 0d782d6..7836438 100644
--- a/src/main/java/com/android/tools/r8/dex/Segment.java
+++ b/src/main/java/com/android/tools/r8/dex/Segment.java
@@ -71,6 +71,7 @@
}
}
+ @Override
public String toString() {
return typeName() + " @" + offset + " " + length;
}
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 cbca177..e2519e3 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -226,7 +226,8 @@
super(writer);
}
- public Map<Integer, VirtualFile> run() throws ExecutionException, IOException {
+ @Override
+ public Map<Integer, VirtualFile> run() {
// Assign dedicated virtual files for all program classes.
for (DexProgramClass clazz : application.classes()) {
VirtualFile file = new VirtualFile(nameToFileMap.size(), writer.namingLens);
@@ -322,7 +323,8 @@
this.fillStrategy = FillStrategy.FILL_MAX;
}
- public Map<Integer, VirtualFile> run() throws ExecutionException, IOException {
+ @Override
+ public Map<Integer, VirtualFile> run() throws IOException {
// First fill required classes into the main dex file.
fillForMainDexList(classes);
if (classes.isEmpty()) {
@@ -381,6 +383,7 @@
this.executorService = executorService;
}
+ @Override
public Map<Integer, VirtualFile> run() throws ExecutionException, IOException {
// Strategy for distributing classes for write out:
// 1. Place all files in the package distribution file in the proposed files (if any).
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 3845507..0ae2cbc 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -3,6 +3,7 @@
// 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;
@@ -13,7 +14,8 @@
public abstract class Code extends CachedHashValueDexItem {
- public abstract IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options);
+ public abstract IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options)
+ throws ApiLevelException;
public abstract void registerReachableDefinitions(UseRegistry registry);
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 3f492b5..50c22b8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.base.MoreObjects;
import java.util.Arrays;
import java.util.function.Consumer;
@@ -91,6 +92,16 @@
}
}
+ public <E extends Throwable> void forEachMethodThrowing(
+ ThrowingConsumer<DexEncodedMethod, E> consumer) throws E {
+ for (DexEncodedMethod method : directMethods()) {
+ consumer.accept(method);
+ }
+ for (DexEncodedMethod method : virtualMethods()) {
+ consumer.accept(method);
+ }
+ }
+
public DexEncodedMethod[] allMethodsSorted() {
int vLen = virtualMethods().length;
int dLen = directMethods().length;
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 f62dda0..1a8602c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -3,6 +3,7 @@
// 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;
@@ -147,7 +148,8 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options) {
+ public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options)
+ throws ApiLevelException {
DexSourceCode source = new DexSourceCode(this, encodedMethod);
IRBuilder builder = new IRBuilder(encodedMethod, source, options);
return builder.build();
@@ -156,7 +158,8 @@
public IRCode buildIR(
DexEncodedMethod encodedMethod,
ValueNumberGenerator valueNumberGenerator,
- InternalOptions options) {
+ InternalOptions options)
+ throws ApiLevelException {
DexSourceCode source = new DexSourceCode(this, encodedMethod);
IRBuilder builder = new IRBuilder(encodedMethod, source, valueNumberGenerator, options);
return builder.build();
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 e66b984..8c071c8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -9,6 +9,7 @@
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.code.Const;
import com.android.tools.r8.code.ConstString;
import com.android.tools.r8.code.ConstStringJumbo;
@@ -25,6 +26,7 @@
import com.android.tools.r8.ir.code.ValueNumberGenerator;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
@@ -106,13 +108,13 @@
return accessFlags.isConstructor() && accessFlags.isStatic();
}
- public boolean isInliningCandidate(DexEncodedMethod container, boolean alwaysInline,
+ public boolean isInliningCandidate(DexEncodedMethod container, Reason inliningReason,
AppInfoWithSubtyping appInfo) {
if (isClassInitializer()) {
// This will probably never happen but never inline a class initializer.
return false;
}
- if (alwaysInline) {
+ if (inliningReason == Reason.FORCE) {
return true;
}
switch (compilationState) {
@@ -155,11 +157,12 @@
compilationState = CompilationState.NOT_PROCESSED;
}
- public IRCode buildIR(InternalOptions options) {
+ public IRCode buildIR(InternalOptions options) throws ApiLevelException {
return code == null ? null : code.buildIR(this, options);
}
- public IRCode buildIR(ValueNumberGenerator valueNumberGenerator, InternalOptions options) {
+ public IRCode buildIR(ValueNumberGenerator valueNumberGenerator, InternalOptions options)
+ throws ApiLevelException {
return code == null
? null
: code.asDexCode().buildIR(this, valueNumberGenerator, options);
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 6b9c06d..1dc5964 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -3,6 +3,7 @@
// 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.ir.code.IRCode;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
@@ -80,7 +81,8 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options) {
+ public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options)
+ throws ApiLevelException {
triggerDelayedParsingIfNeccessary();
return options.debug
? internalBuildWithLocals(encodedMethod, null, options)
@@ -88,7 +90,8 @@
}
public IRCode buildIR(
- DexEncodedMethod encodedMethod, ValueNumberGenerator generator, InternalOptions options) {
+ DexEncodedMethod encodedMethod, ValueNumberGenerator generator, InternalOptions options)
+ throws ApiLevelException {
assert generator != null;
triggerDelayedParsingIfNeccessary();
return options.debug
@@ -97,7 +100,8 @@
}
private IRCode internalBuildWithLocals(
- DexEncodedMethod encodedMethod, ValueNumberGenerator generator, InternalOptions options) {
+ DexEncodedMethod encodedMethod, ValueNumberGenerator generator, InternalOptions options)
+ throws ApiLevelException {
try {
return internalBuild(encodedMethod, generator, options);
} catch (InvalidDebugInfoException e) {
@@ -108,7 +112,8 @@
}
private IRCode internalBuild(
- DexEncodedMethod encodedMethod, ValueNumberGenerator generator, InternalOptions options) {
+ DexEncodedMethod encodedMethod, ValueNumberGenerator generator, InternalOptions options)
+ throws ApiLevelException {
if (!options.debug) {
node.localVariables.clear();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
index f5bc204..40a4776 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
@@ -140,29 +140,13 @@
assert newInstruction.outValue() != null;
current.outValue().replaceUsers(newInstruction.outValue());
}
- for (Value value : current.getDebugValues()) {
- replaceInstructionInList(current, newInstruction, value.getDebugLocalStarts());
- replaceInstructionInList(current, newInstruction, value.getDebugLocalEnds());
- value.removeDebugUser(current);
- newInstruction.addDebugValue(value);
- }
+ current.moveDebugValues(newInstruction);
newInstruction.setBlock(block);
listIterator.remove();
listIterator.add(newInstruction);
current.clearBlock();
}
- private static void replaceInstructionInList(
- Instruction instruction,
- Instruction newInstruction,
- List<Instruction> instructions) {
- for (int i = 0; i < instructions.size(); i++) {
- if (instructions.get(i) == instruction) {
- instructions.set(i, newInstruction);
- }
- }
- }
-
public BasicBlock split(IRCode code, ListIterator<BasicBlock> blocksIterator) {
List<BasicBlock> blocks = code.blocks;
assert blocksIterator == null || IteratorUtils.peekPrevious(blocksIterator) == block;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index e99dbf1..52fff08 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -74,8 +74,9 @@
if (debugValues == null) {
debugValues = new HashSet<>();
}
- debugValues.add(value);
- value.addDebugUser(this);
+ if (debugValues.add(value)) {
+ value.addDebugUser(this);
+ }
}
public static void clearUserInfo(Instruction instruction) {
@@ -94,19 +95,17 @@
public abstract void buildDex(DexBuilder builder);
- public void replaceValue(Value oldValue, Value newValue, List<Instruction> toRemove) {
+ public void replaceValue(Value oldValue, Value newValue) {
for (int i = 0; i < inValues.size(); i++) {
if (oldValue == inValues.get(i)) {
inValues.set(i, newValue);
newValue.addUser(this);
- toRemove.add(this);
}
}
}
- public void replaceDebugValue(Value oldValue, Value newValue, List<Instruction> toRemove) {
+ public void replaceDebugValue(Value oldValue, Value newValue) {
if (debugValues.remove(oldValue)) {
- toRemove.add(this);
if (newValue.getLocalInfo() != null) {
// TODO(zerny): Insert a write if replacing a phi with different debug-local info.
addDebugValue(newValue);
@@ -115,6 +114,16 @@
}
}
+ public void moveDebugValues(Instruction target) {
+ if (debugValues == null) {
+ return;
+ }
+ for (Value value : debugValues) {
+ value.replaceDebugUser(this, target);
+ }
+ debugValues.clear();
+ }
+
/**
* Returns the basic block containing this instruction.
*/
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java
index 96069bf..20dc3c7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Phi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -155,22 +155,20 @@
current.removePhiUser(this);
}
- void replaceTrivialPhi(Value current, Value newValue, List<Phi> toRemove) {
+ void replaceOperand(Value current, Value newValue) {
for (int i = 0; i < operands.size(); i++) {
if (operands.get(i) == current) {
operands.set(i, newValue);
newValue.addPhiUser(this);
- toRemove.add(this);
}
}
}
- void replaceTrivialDebugPhi(Value current, Value newValue, List<Phi> toRemove) {
+ void replaceDebugValue(Value current, Value newValue) {
assert current.getLocalInfo() != null;
assert current.getLocalInfo() == newValue.getLocalInfo();
if (debugValues.remove(current)) {
addDebugValue(newValue);
- toRemove.add(this);
}
}
@@ -228,7 +226,7 @@
{
Set<Phi> phiUsersToSimplify = uniquePhiUsers();
// Replace this phi with the unique value in all users.
- replaceInUsers(same);
+ replaceUsers(same);
// Try to simplify phi users that might now have become trivial.
for (Phi user : phiUsersToSimplify) {
user.removeTrivialPhi();
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index dfa8548..62a1152 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
import com.android.tools.r8.utils.InternalOptions;
@@ -11,9 +12,12 @@
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
public class Value {
@@ -21,17 +25,49 @@
// Lazily allocated internal data for the debug information of locals.
// This is wrapped in a class to avoid multiple pointers in the value structure.
private static class DebugData {
+
final DebugLocalInfo local;
- Set<Instruction> users = new HashSet<>();
+ Map<Instruction, DebugUse> users = new HashMap<>();
Set<Phi> phiUsers = new HashSet<>();
- List<Instruction> localStarts = new ArrayList<>();
- List<Instruction> localEnds = new ArrayList<>();
DebugData(DebugLocalInfo local) {
this.local = local;
}
}
+ // A debug-value user represents a point where the value is live, ends or starts.
+ // If a point is marked as both ending and starting then it is simply live, but we maintain
+ // the marker so as not to unintentionally end it if marked again.
+ private enum DebugUse {
+ LIVE, START, END, LIVE_FINAL;
+
+ DebugUse start() {
+ switch (this) {
+ case LIVE:
+ case START:
+ return START;
+ case END:
+ case LIVE_FINAL:
+ return LIVE_FINAL;
+ default:
+ throw new Unreachable();
+ }
+ }
+
+ DebugUse end() {
+ switch (this) {
+ case LIVE:
+ case END:
+ return END;
+ case START:
+ case LIVE_FINAL:
+ return LIVE_FINAL;
+ default:
+ throw new Unreachable();
+ }
+ }
+ }
+
public static final Value UNDEFINED = new Value(-1, MoveType.OBJECT, null);
protected final int number;
@@ -79,21 +115,49 @@
}
public List<Instruction> getDebugLocalStarts() {
- return debugData.localStarts;
+ if (debugData == null) {
+ return Collections.emptyList();
+ }
+ List<Instruction> starts = new ArrayList<>(debugData.users.size());
+ for (Entry<Instruction, DebugUse> entry : debugData.users.entrySet()) {
+ if (entry.getValue() == DebugUse.START) {
+ starts.add(entry.getKey());
+ }
+ }
+ return starts;
}
public List<Instruction> getDebugLocalEnds() {
- return debugData.localEnds;
+ if (debugData == null) {
+ return Collections.emptyList();
+ }
+ List<Instruction> ends = new ArrayList<>(debugData.users.size());
+ for (Entry<Instruction, DebugUse> entry : debugData.users.entrySet()) {
+ if (entry.getValue() == DebugUse.END) {
+ ends.add(entry.getKey());
+ }
+ }
+ return ends;
}
public void addDebugLocalStart(Instruction start) {
assert start != null;
- debugData.localStarts.add(start);
+ debugData.users.put(start, markStart(debugData.users.get(start)));
+ }
+
+ private DebugUse markStart(DebugUse use) {
+ assert use != null;
+ return use == null ? DebugUse.START : use.start();
}
public void addDebugLocalEnd(Instruction end) {
assert end != null;
- debugData.localEnds.add(end);
+ debugData.users.put(end, markEnd(debugData.users.get(end)));
+ }
+
+ private DebugUse markEnd(DebugUse use) {
+ assert use != null;
+ return use == null ? DebugUse.END : use.end();
}
public void linkTo(Value other) {
@@ -152,7 +216,7 @@
}
public Set<Instruction> debugUsers() {
- return debugData == null ? null : Collections.unmodifiableSet(debugData.users);
+ return debugData == null ? null : Collections.unmodifiableSet(debugData.users.keySet());
}
public Set<Phi> debugPhiUsers() {
@@ -244,7 +308,7 @@
if (isUninitializedLocal()) {
return;
}
- debugData.users.add(user);
+ debugData.users.putIfAbsent(user, DebugUse.LIVE);
}
public void addDebugPhiUser(Phi user) {
@@ -263,11 +327,19 @@
}
public void removeDebugUser(Instruction user) {
- debugData.users.remove(user);
+ if (debugData != null && debugData.users != null) {
+ debugData.users.remove(user);
+ return;
+ }
+ assert false;
}
public void removeDebugPhiUser(Phi user) {
- debugData.phiUsers.remove(user);
+ if (debugData != null && debugData.phiUsers != null) {
+ debugData.phiUsers.remove(user);
+ return;
+ }
+ assert false;
}
public boolean hasUsersInfo() {
@@ -290,68 +362,27 @@
return;
}
for (Instruction user : uniqueUsers()) {
- user.inValues.replaceAll(v -> {
- if (v == this) {
- newValue.addUser(user);
- return newValue;
- }
- return v;
- });
+ user.replaceValue(this, newValue);
}
for (Phi user : uniquePhiUsers()) {
- user.getOperands().replaceAll(v -> {
- if (v == this) {
- newValue.addPhiUser(user);
- return newValue;
- }
- return v;
- });
+ user.replaceOperand(this, newValue);
}
if (debugData != null) {
for (Instruction user : debugUsers()) {
- if (user.getDebugValues().remove(this)) {
- user.addDebugValue(newValue);
- }
+ user.replaceDebugValue(this, newValue);
}
for (Phi user : debugPhiUsers()) {
- if (user.getDebugValues().remove(this)) {
- user.addDebugValue(newValue);
- }
+ user.replaceDebugValue(this, newValue);
}
}
clearUsers();
}
- public void replaceInUsers(Value newValue) {
- if (!uniqueUsers().isEmpty()) {
- List<Instruction> toRemove = new ArrayList<>(uniqueUsers().size());
- for (Instruction user : uniqueUsers()) {
- user.replaceValue(this, newValue, toRemove);
- }
- toRemove.forEach(this::removeUser);
- }
- if (!uniquePhiUsers().isEmpty()) {
- List<Phi> toRemove = new ArrayList<>(uniquePhiUsers().size());
- for (Phi user : uniquePhiUsers()) {
- user.replaceTrivialPhi(this, newValue, toRemove);
- }
- toRemove.forEach(this::removePhiUser);
- }
- if (debugData != null) {
- if (!debugUsers().isEmpty()) {
- List<Instruction> toRemove = new ArrayList<>(debugUsers().size());
- for (Instruction user : debugUsers()) {
- user.replaceDebugValue(this, newValue, toRemove);
- }
- toRemove.forEach(this::removeDebugUser);
- }
- if (!debugPhiUsers().isEmpty()) {
- List<Phi> toRemove = new ArrayList<>(debugPhiUsers().size());
- for (Phi user : debugPhiUsers()) {
- user.replaceTrivialDebugPhi(this, newValue, toRemove);
- }
- toRemove.forEach(this::removeDebugPhiUser);
- }
+ public void replaceDebugUser(Instruction oldUser, Instruction newUser) {
+ DebugUse use = debugData.users.remove(oldUser);
+ if (use != null) {
+ newUser.addDebugValue(this);
+ debugData.users.put(newUser, use);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index dad58d8..b32f34d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -18,11 +18,11 @@
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.ThrowingBiConsumer;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -31,8 +31,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
-import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -50,7 +50,7 @@
* <p>
* Recursive calls are not present.
*/
-public class CallGraph {
+public class CallGraph extends CallSiteInformation {
private CallGraph(InternalOptions options) {
this.shuffle = options.testing.irOrdering;
@@ -131,15 +131,7 @@
}
private final Map<DexEncodedMethod, Node> nodes = new LinkedHashMap<>();
- private final Map<DexEncodedMethod, Set<DexEncodedMethod>> breakers = new HashMap<>();
- private final Function<List<DexEncodedMethod>, List<DexEncodedMethod>> shuffle;
-
- // Returns whether the method->callee edge has been removed from the call graph
- // to break a cycle in the call graph.
- public boolean isBreaker(DexEncodedMethod method, DexEncodedMethod callee) {
- Set<DexEncodedMethod> value = breakers.get(method);
- return (value != null) && value.contains(callee);
- }
+ private final Function<Set<DexEncodedMethod>, Set<DexEncodedMethod>> shuffle;
private Set<DexEncodedMethod> singleCallSite = Sets.newIdentityHashSet();
private Set<DexEncodedMethod> doubleCallSite = Sets.newIdentityHashSet();
@@ -169,10 +161,12 @@
* For pinned methods (methods kept through Proguard keep rules) this will always answer
* <code>false</code>.
*/
+ @Override
public boolean hasSingleCallSite(DexEncodedMethod method) {
return singleCallSite.contains(method);
}
+ @Override
public boolean hasDoubleCallSite(DexEncodedMethod method) {
return doubleCallSite.contains(method);
}
@@ -210,12 +204,10 @@
* All nodes in the graph are extracted if called repeatedly until null is returned.
* Please note that there are no cycles in this graph (see {@link #breakCycles}).
* <p>
- *
- * @return List of {@link DexEncodedMethod}.
*/
- private List<DexEncodedMethod> extractLeaves() {
+ private Set<DexEncodedMethod> extractLeaves() {
if (isEmpty()) {
- return Collections.emptyList();
+ return Collections.emptySet();
}
// First identify all leaves before removing them from the graph.
List<Node> leaves = nodes.values().stream().filter(Node::isLeaf).collect(Collectors.toList());
@@ -223,7 +215,8 @@
leaf.callers.forEach(caller -> caller.callees.remove(leaf));
nodes.remove(leaf.method);
});
- return shuffle.apply(leaves.stream().map(leaf -> leaf.method).collect(Collectors.toList()));
+ return shuffle.apply(leaves.stream().map(leaf -> leaf.method)
+ .collect(Collectors.toCollection(LinkedHashSet::new)));
}
private int traverse(Node node, Set<Node> stack, Set<Node> marked) {
@@ -245,8 +238,6 @@
// We have a cycle; break it by removing node->callee.
toBeRemoved.add(callee);
callee.callers.remove(node);
- breakers.computeIfAbsent(node.method,
- ignore -> Sets.newIdentityHashSet()).add(callee.method);
} else {
numberOfCycles += traverse(callee, stack, marked);
}
@@ -263,7 +254,6 @@
private int breakCycles() {
// Break cycles in this call graph by removing edges causing cycles.
- // The remove edges are stored in @breakers.
int numberOfCycles = 0;
Set<Node> stack = Sets.newIdentityHashSet();
Set<Node> marked = Sets.newIdentityHashSet();
@@ -293,15 +283,24 @@
return nodes.size() == 0;
}
- public void forEachMethod(Consumer<DexEncodedMethod> consumer, ExecutorService executorService)
+ /**
+ * Applies the given method to all leaf nodes of the graph.
+ * <p>
+ * As second parameter, a predicate that can be used to decide whether another method is
+ * processed at the same time is passed. This can be used to avoid races in concurrent processing.
+ */
+ public <E extends Exception> void forEachMethod(
+ ThrowingBiConsumer<DexEncodedMethod, Predicate<DexEncodedMethod>, E> consumer,
+ ExecutorService executorService)
throws ExecutionException {
while (!isEmpty()) {
- List<DexEncodedMethod> methods = extractLeaves();
+ Set<DexEncodedMethod> methods = extractLeaves();
assert methods.size() > 0;
List<Future<?>> futures = new ArrayList<>();
for (DexEncodedMethod method : methods) {
futures.add(executorService.submit(() -> {
- consumer.accept(method);
+ consumer.accept(method, methods::contains);
+ return null; // we want a Callable not a Runnable to be able to throw
}));
}
ThreadUtils.awaitFutures(futures);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java b/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
new file mode 100644
index 0000000..651fb6f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
@@ -0,0 +1,38 @@
+// 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.ir.conversion;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+
+public abstract class CallSiteInformation {
+
+ /**
+ * Check if the <code>method</code> is guaranteed to only have a single call site.
+ * <p>
+ * For pinned methods (methods kept through Proguard keep rules) this will always answer
+ * <code>false</code>.
+ */
+ public abstract boolean hasSingleCallSite(DexEncodedMethod method);
+
+ public abstract boolean hasDoubleCallSite(DexEncodedMethod method);
+
+ public static CallSiteInformation empty() {
+ return EmptyCallSiteInformation.EMPTY_INFO;
+ }
+
+ private static class EmptyCallSiteInformation extends CallSiteInformation {
+
+ private static EmptyCallSiteInformation EMPTY_INFO = new EmptyCallSiteInformation();
+
+ @Override
+ public boolean hasSingleCallSite(DexEncodedMethod method) {
+ return false;
+ }
+
+ @Override
+ public boolean hasDoubleCallSite(DexEncodedMethod method) {
+ return false;
+ }
+ }
+}
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 9e07ad6..bc821d3 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,6 +4,7 @@
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;
@@ -148,7 +149,7 @@
}
@Override
- public void buildInstruction(IRBuilder builder, int instructionIndex) {
+ public void buildInstruction(IRBuilder builder, int instructionIndex) throws ApiLevelException {
updateCurrentCatchHandlers(instructionIndex);
emitDebugPosition(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 7f7b726..5eeda96 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
@@ -4,6 +4,7 @@
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.InternalCompilerError;
@@ -311,7 +312,7 @@
*
* @return The list of basic blocks. First block is the main entry.
*/
- public IRCode build() {
+ public IRCode build() throws ApiLevelException {
assert source != null;
source.setUp();
@@ -441,7 +442,7 @@
return true;
}
- private void processWorklist() {
+ private void processWorklist() throws ApiLevelException {
for (WorklistItem item = ssaWorklist.poll(); item != null; item = ssaWorklist.poll()) {
if (item.block.isFilled()) {
continue;
@@ -917,12 +918,14 @@
add(instruction);
}
- public void addInvoke(
- Type type, DexItem item, DexProto callSiteProto, List<Value> arguments) {
+ public void addInvoke(Type type, DexItem item, DexProto callSiteProto, List<Value> arguments)
+ throws ApiLevelException {
if (type == Invoke.Type.POLYMORPHIC && !options.canUseInvokePolymorphic()) {
- throw new CompilationError(
- "MethodHandle.invoke and MethodHandle.invokeExact is unsupported before "
- + "Android O (--min-api " + Constants.ANDROID_O_API + ")");
+ throw new ApiLevelException(
+ Constants.ANDROID_O_API,
+ "Android O",
+ "MethodHandle.invoke and MethodHandle.invokeExact",
+ null /* sourceString */);
}
add(Invoke.create(type, item, callSiteProto, null, arguments));
}
@@ -932,7 +935,8 @@
DexItem item,
DexProto callSiteProto,
List<MoveType> types,
- List<Integer> registers) {
+ List<Integer> registers)
+ throws ApiLevelException {
assert types.size() == registers.size();
List<Value> arguments = new ArrayList<>(types.size());
for (int i = 0; i < types.size(); i++) {
@@ -1000,7 +1004,8 @@
DexMethod method,
DexProto callSiteProto,
int argumentRegisterCount,
- int[] argumentRegisters) {
+ int[] argumentRegisters)
+ throws ApiLevelException {
// 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);
@@ -1027,7 +1032,8 @@
addInvoke(type, method, callSiteProto, arguments);
}
- public void addInvokeNewArray(DexType type, int argumentCount, int[] argumentRegisters) {
+ public void addInvokeNewArray(DexType type, int argumentCount, int[] argumentRegisters)
+ throws ApiLevelException {
String descriptor = type.descriptor.toString();
assert descriptor.charAt(0) == '[';
assert descriptor.length() >= 2;
@@ -1051,7 +1057,8 @@
DexMethod method,
DexProto callSiteProto,
int argumentCount,
- int firstArgumentRegister) {
+ int firstArgumentRegister)
+ throws ApiLevelException {
// 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);
@@ -1078,7 +1085,8 @@
addInvoke(type, method, callSiteProto, arguments);
}
- public void addInvokeRangeNewArray(DexType type, int argumentCount, int firstArgumentRegister) {
+ public void addInvokeRangeNewArray(DexType type, int argumentCount, int firstArgumentRegister)
+ throws ApiLevelException {
String descriptor = type.descriptor.toString();
assert descriptor.charAt(0) == '[';
assert descriptor.length() >= 2;
@@ -1792,12 +1800,7 @@
}
Goto gotoExit = new Goto();
gotoExit.setBlock(block);
- if (options.debug) {
- for (Value value : ret.getDebugValues()) {
- gotoExit.addDebugValue(value);
- value.removeDebugUser(ret);
- }
- }
+ ret.moveDebugValues(gotoExit);
instructions.set(instructions.size() - 1, gotoExit);
block.link(normalExitBlock);
gotoExit.setTarget(normalExitBlock);
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 fad378e..ea1ef57 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,6 +6,7 @@
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;
@@ -47,6 +48,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.BiConsumer;
+import java.util.function.Predicate;
public class IRConverter {
@@ -66,7 +68,6 @@
private final LensCodeRewriter lensCodeRewriter;
private final Inliner inliner;
private final ProtoLitePruner protoLiteRewriter;
- private CallGraph callGraph;
private OptimizationFeedback ignoreOptimizationFeedback = new OptimizationFeedbackIgnore();
private DexString highestSortingString;
@@ -196,7 +197,7 @@
}
}
- private void synthesizeLambdaClasses(Builder builder) {
+ private void synthesizeLambdaClasses(Builder builder) throws ApiLevelException {
if (lambdaRewriter != null) {
lambdaRewriter.adjustAccessibility();
lambdaRewriter.synthesizeLambdaClasses(builder);
@@ -204,13 +205,15 @@
}
private void desugarInterfaceMethods(
- Builder builder, InterfaceMethodRewriter.Flavor includeAllResources) {
+ Builder builder, InterfaceMethodRewriter.Flavor includeAllResources)
+ throws ApiLevelException {
if (interfaceMethodRewriter != null) {
interfaceMethodRewriter.desugarInterfaceMethods(builder, includeAllResources);
}
}
- public DexApplication convertToDex(ExecutorService executor) throws ExecutionException {
+ public DexApplication convertToDex(ExecutorService executor)
+ throws ExecutionException, ApiLevelException {
removeLambdaDeserializationMethods();
convertClassesToDex(application.classes(), executor);
@@ -229,28 +232,34 @@
ExecutorService executor) throws ExecutionException {
List<Future<?>> futures = new ArrayList<>();
for (DexProgramClass clazz : classes) {
- futures.add(executor.submit(() -> clazz.forEachMethod(this::convertMethodToDex)));
+ futures.add(
+ executor.submit(
+ () -> {
+ clazz.forEachMethodThrowing(this::convertMethodToDex);
+ return null; // we want a Callable not a Runnable to be able to throw
+ }));
}
-
ThreadUtils.awaitFutures(futures);
// Get rid of <clinit> methods with no code.
removeEmptyClassInitializers();
}
- private void convertMethodToDex(DexEncodedMethod method) {
+ void convertMethodToDex(DexEncodedMethod method) throws ApiLevelException {
if (method.getCode() != null) {
boolean matchesMethodFilter = options.methodMatchesFilter(method);
if (matchesMethodFilter) {
if (method.getCode().isJarCode()) {
- rewriteCode(method, ignoreOptimizationFeedback, Outliner::noProcessing);
+ // We do not process in call graph order, so anything could be a leaf.
+ rewriteCode(method, ignoreOptimizationFeedback, x -> true, CallSiteInformation.empty(),
+ Outliner::noProcessing);
}
updateHighestSortingStrings(method);
}
}
}
- public DexApplication optimize() throws ExecutionException {
+ public DexApplication optimize() throws ExecutionException, ApiLevelException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
return optimize(executor);
@@ -259,13 +268,10 @@
}
}
- public DexApplication optimize(ExecutorService executorService) throws ExecutionException {
+ public DexApplication optimize(ExecutorService executorService)
+ throws ExecutionException, ApiLevelException {
removeLambdaDeserializationMethods();
- timing.begin("Build call graph");
- callGraph = CallGraph.build(application, appInfo.withSubtyping(), graphLense, options);
- timing.end();
-
// The process is in two phases.
// 1) Subject all DexEncodedMethods to optimization (except outlining).
// - a side effect is candidates for outlining are identified.
@@ -273,13 +279,19 @@
// Ideally, we should outline eagerly when threshold for a template has been reached.
// Process the application identifying outlining candidates.
- timing.begin("IR conversion phase 1");
OptimizationFeedback directFeedback = new OptimizationFeedbackDirect();
- callGraph.forEachMethod(method -> {
- processMethod(method, directFeedback,
- outliner == null ? Outliner::noProcessing : outliner::identifyCandidates);
- }, executorService);
- timing.end();
+ {
+ timing.begin("Build call graph");
+ CallGraph callGraph = CallGraph
+ .build(application, appInfo.withSubtyping(), 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);
+ timing.end();
+ }
// Get rid of <clinit> methods with no code.
removeEmptyClassInitializers();
@@ -304,16 +316,17 @@
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 callGraph = CallGraph
.build(application, appInfo.withSubtyping(), GraphLense.getIdentityLense(), options);
Set<DexEncodedMethod> outlineMethods = outliner.getMethodsSelectedForOutlining();
- callGraph.forEachMethod(method -> {
+ 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, outliner::applyOutliningCandidate);
+ processMethod(method, ignoreOptimizationFeedback, isProcessedConcurrently, callGraph,
+ outliner::applyOutliningCandidate);
assert method.isProcessed();
}, executorService);
builder.addSynthesizedClass(outlineClass, true);
@@ -380,7 +393,7 @@
return result;
}
- private DexProgramClass prepareOutlining() {
+ private DexProgramClass prepareOutlining() throws ApiLevelException {
if (!outliner.selectMethodsForOutlining()) {
return null;
}
@@ -389,14 +402,15 @@
return outlineClass;
}
- public void optimizeSynthesizedClass(DexProgramClass clazz) {
+ public void optimizeSynthesizedClass(DexProgramClass clazz) throws ApiLevelException {
// Process the generated class, but don't apply any outlining.
- clazz.forEachMethod(this::optimizeSynthesizedMethod);
+ clazz.forEachMethodThrowing(this::optimizeSynthesizedMethod);
}
- public void optimizeSynthesizedMethod(DexEncodedMethod method) {
+ public void optimizeSynthesizedMethod(DexEncodedMethod method) throws ApiLevelException {
// Process the generated method, but don't apply any outlining.
- processMethod(method, ignoreOptimizationFeedback, Outliner::noProcessing);
+ processMethod(method, ignoreOptimizationFeedback, x -> false, CallSiteInformation.empty(),
+ Outliner::noProcessing);
}
private String logCode(InternalOptions options, DexEncodedMethod method) {
@@ -405,11 +419,14 @@
public void processMethod(DexEncodedMethod method,
OptimizationFeedback feedback,
- BiConsumer<IRCode, DexEncodedMethod> outlineHandler) {
+ Predicate<DexEncodedMethod> isProcessedConcurrently,
+ CallSiteInformation callSiteInformation,
+ BiConsumer<IRCode, DexEncodedMethod> outlineHandler)
+ throws ApiLevelException {
Code code = method.getCode();
boolean matchesMethodFilter = options.methodMatchesFilter(method);
if (code != null && matchesMethodFilter) {
- rewriteCode(method, feedback, outlineHandler);
+ rewriteCode(method, feedback, isProcessedConcurrently, callSiteInformation, outlineHandler);
} else {
// Mark abstract methods as processed as well.
method.markProcessed(Constraint.NEVER);
@@ -418,7 +435,10 @@
private void rewriteCode(DexEncodedMethod method,
OptimizationFeedback feedback,
- BiConsumer<IRCode, DexEncodedMethod> outlineHandler) {
+ Predicate<DexEncodedMethod> isProcessedConcurrently,
+ CallSiteInformation callSiteInformation,
+ BiConsumer<IRCode, DexEncodedMethod> outlineHandler)
+ throws ApiLevelException {
if (options.verbose) {
System.out.println("Processing: " + method.toSourceString());
}
@@ -462,7 +482,7 @@
if (options.inlineAccessors && inliner != null) {
// TODO(zerny): Should we support inlining in debug mode? b/62937285
assert !options.debug;
- inliner.performInlining(method, code, callGraph);
+ inliner.performInlining(method, code, isProcessedConcurrently, callSiteInformation);
}
codeRewriter.removeCastChains(code);
codeRewriter.rewriteLongCompareAndRequireNonNull(code, options);
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 e22b2f3..fdc4743 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,6 +3,7 @@
// 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;
@@ -32,6 +33,7 @@
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;
@@ -47,7 +49,6 @@
import java.util.Map;
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;
@@ -477,7 +478,7 @@
}
@Override
- public void buildInstruction(IRBuilder builder, int instructionIndex) {
+ public void buildInstruction(IRBuilder builder, int instructionIndex) throws ApiLevelException {
if (instructionIndex == EXCEPTIONAL_SYNC_EXIT_OFFSET) {
buildExceptionalPostlude(builder);
return;
@@ -1793,7 +1794,7 @@
// IR instruction building procedures.
- private void build(AbstractInsnNode insn, IRBuilder builder) {
+ private void build(AbstractInsnNode insn, IRBuilder builder) throws ApiLevelException {
switch (insn.getType()) {
case AbstractInsnNode.INSN:
build((InsnNode) insn, builder);
@@ -2521,7 +2522,7 @@
}
}
- private void build(MethodInsnNode insn, IRBuilder builder) {
+ private void build(MethodInsnNode insn, IRBuilder builder) throws ApiLevelException {
// Resolve the target method of the invoke.
DexMethod method = application.getMethod(insn.owner, insn.name, insn.desc);
@@ -2544,8 +2545,12 @@
}
private void buildInvoke(
- String methodDesc, Type methodOwner, boolean addImplicitReceiver,
- IRBuilder builder, BiConsumer<List<MoveType>, List<Integer>> creator) {
+ String methodDesc,
+ Type methodOwner,
+ boolean addImplicitReceiver,
+ IRBuilder builder,
+ ThrowingBiConsumer<List<MoveType>, List<Integer>, ApiLevelException> creator)
+ throws ApiLevelException {
// 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.
@@ -2586,7 +2591,7 @@
registers.add(slot.register);
}
- private void build(InvokeDynamicInsnNode insn, IRBuilder builder) {
+ private void build(InvokeDynamicInsnNode insn, IRBuilder builder) throws ApiLevelException {
// Bootstrap method
Handle bsmHandle = insn.bsm;
if (bsmHandle.getTag() != Opcodes.H_INVOKESTATIC &&
@@ -2786,7 +2791,7 @@
builder.addSwitch(index, keys, fallthroughOffset, labelOffsets);
}
- private void build(MultiANewArrayInsnNode insn, IRBuilder builder) {
+ private void build(MultiANewArrayInsnNode insn, IRBuilder builder) throws ApiLevelException {
// Type of the full array.
Type arrayType = Type.getObjectType(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 b1f9a14..cf1e669 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,6 +4,7 @@
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;
@@ -46,7 +47,7 @@
// Delegates for IR building.
void buildPrelude(IRBuilder builder);
- void buildInstruction(IRBuilder builder, int instructionIndex);
+ void buildInstruction(IRBuilder builder, int instructionIndex) throws ApiLevelException;
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/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index c3f2d08..cbeda1e 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,6 +4,7 @@
package com.android.tools.r8.ir.desugar;
+import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.Resource;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
@@ -193,7 +194,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) {
+ public void desugarInterfaceMethods(Builder builder, Flavor flavour) throws ApiLevelException {
// 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 353f866..f03a619 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,6 +4,7 @@
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;
@@ -387,7 +388,7 @@
}
// Ensure access of the referenced symbol(s).
- abstract boolean ensureAccessibility();
+ abstract boolean ensureAccessibility() throws ApiLevelException;
DexClass definitionFor(DexType type) {
return rewriter.converter.appInfo.app.definitionFor(type);
@@ -482,7 +483,7 @@
}
@Override
- boolean ensureAccessibility() {
+ boolean ensureAccessibility() throws ApiLevelException {
// 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/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
index e322717..bba7b23 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
-import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
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 f6f8f2c..86ad391 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,6 +4,7 @@
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;
@@ -191,7 +192,7 @@
* Adjust accessibility of referenced application symbols or
* creates necessary accessors.
*/
- public void adjustAccessibility() {
+ public void adjustAccessibility() throws ApiLevelException {
// 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.
@@ -201,7 +202,7 @@
}
/** Generates lambda classes and adds them to the builder. */
- public void synthesizeLambdaClasses(Builder builder) {
+ public void synthesizeLambdaClasses(Builder builder) throws ApiLevelException {
for (LambdaClass lambdaClass : knownLambdaClasses.values()) {
DexProgramClass synthesizedClass = lambdaClass.synthesizeLambdaClass();
converter.optimizeSynthesizedClass(synthesizedClass);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
index 9f833f0..8820c61 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.google.common.base.Equivalence;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.List;
class BasicBlockInstructionsEquivalence extends Equivalence<BasicBlock> {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index d44ecd9..a758223 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -1101,18 +1101,18 @@
// Add constant into the dominator block of usages.
insertConstantInBlock(instruction, entry.getKey());
} else {
- assert instruction.outValue().numberOfUsers() != 0;
ConstNumber constNumber = instruction.asConstNumber();
Value constantValue = instruction.outValue();
- List<Instruction> toRemove = new ArrayList<>(constantValue.uniqueUsers().size());
+ assert constantValue.numberOfUsers() != 0;
+ assert constantValue.numberOfUsers() == constantValue.numberOfAllUsers();
for (Instruction user : constantValue.uniqueUsers()) {
ConstNumber newCstNum = ConstNumber.copyOf(code, constNumber);
InstructionListIterator iterator = user.getBlock().listIterator(user);
iterator.previous();
iterator.add(newCstNum);
- user.replaceValue(constantValue, newCstNum.outValue(), toRemove);
+ user.replaceValue(constantValue, newCstNum.outValue());
}
- toRemove.forEach(constantValue::removeUser);
+ constantValue.clearUsers();
}
}
} else {
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 b2ebecc..38c8da8 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,6 +3,7 @@
// 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;
@@ -47,14 +48,16 @@
return ordinalsMaps.get(enumClass);
}
- public void run() {
- appInfo.classes().forEach(this::processClasses);
+ public void run() throws ApiLevelException {
+ for (DexProgramClass clazz : appInfo.classes()) {
+ processClasses(clazz);
+ }
if (!ordinalsMaps.isEmpty()) {
appInfo.setExtension(EnumOrdinalMapCollector.class, ordinalsMaps);
}
}
- private void processClasses(DexProgramClass clazz) {
+ private void processClasses(DexProgramClass clazz) throws ApiLevelException {
// 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 814812c..a11d924 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,6 +3,7 @@
// 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.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexAccessFlags;
import com.android.tools.r8.graph.DexClass;
@@ -22,7 +23,7 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
-import com.android.tools.r8.ir.conversion.CallGraph;
+import com.android.tools.r8.ir.conversion.CallSiteInformation;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.LensCodeRewriter;
import com.android.tools.r8.ir.conversion.OptimizationFeedback;
@@ -35,6 +36,7 @@
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
public class Inliner {
@@ -127,7 +129,7 @@
}
public synchronized void processDoubleInlineCallers(IRConverter converter,
- OptimizationFeedback feedback) {
+ OptimizationFeedback feedback) throws ApiLevelException {
if (doubleInlineCallers.size() > 0) {
applyDoubleInlining = true;
List<DexEncodedMethod> methods = doubleInlineCallers
@@ -135,7 +137,8 @@
.sorted(DexEncodedMethod::slowCompare)
.collect(Collectors.toList());
for (DexEncodedMethod method : methods) {
- converter.processMethod(method, feedback, Outliner::noProcessing);
+ converter.processMethod(method, feedback, x -> false, CallSiteInformation.empty(),
+ Outliner::noProcessing);
assert method.isProcessed();
}
}
@@ -221,12 +224,12 @@
this.reason = reason;
}
- boolean forceInline() {
+ boolean ignoreInstructionBudget() {
return reason != Reason.SIMPLE;
}
public IRCode buildIR(ValueNumberGenerator generator, AppInfoWithSubtyping appInfo,
- GraphLense graphLense, InternalOptions options) {
+ GraphLense graphLense, InternalOptions options) throws ApiLevelException {
if (target.isProcessed()) {
assert target.getCode().isDexCode();
return target.buildIR(generator, options);
@@ -314,14 +317,18 @@
return true;
}
- public void performInlining(DexEncodedMethod method, IRCode code, CallGraph callGraph) {
+ public void performInlining(DexEncodedMethod method, IRCode code,
+ Predicate<DexEncodedMethod> isProcessedConcurrently,
+ CallSiteInformation callSiteInformation)
+ throws ApiLevelException {
int instruction_allowance = 1500;
instruction_allowance -= numberOfInstructions(code);
if (instruction_allowance < 0) {
return;
}
computeReceiverMustBeNonNull(code);
- InliningOracle oracle = new InliningOracle(this, method, callGraph);
+ InliningOracle oracle = new InliningOracle(this, method, callSiteInformation,
+ isProcessedConcurrently);
List<BasicBlock> blocksToRemove = new ArrayList<>();
ListIterator<BasicBlock> blockIterator = code.listIterator();
@@ -337,15 +344,7 @@
InvokeMethod invoke = current.asInvokeMethod();
InlineAction result = invoke.computeInlining(oracle);
if (result != null) {
- DexEncodedMethod target = appInfo.lookup(invoke.getType(), invoke.getInvokedMethod());
- if (target == null) {
- // The declared target cannot be found so skip inlining.
- continue;
- }
- if (!(target.isProcessed() || result.reason == Reason.FORCE)) {
- // Do not inline code that was not processed unless we have to force inline.
- continue;
- }
+ DexEncodedMethod target = result.target;
IRCode inlinee = result
.buildIR(code.valueNumberGenerator, appInfo, graphLense, options);
if (inlinee != null) {
@@ -353,10 +352,6 @@
if (block.hasCatchHandlers() && inlinee.getNormalExitBlock() == null) {
continue;
}
- if (callGraph.isBreaker(method, target)) {
- // Make sure we don't inline a call graph breaker.
- continue;
- }
// If this code did not go through the full pipeline, apply inlining to make sure
// that force inline targets get processed.
if (!target.isProcessed()) {
@@ -364,7 +359,8 @@
if (Log.ENABLED) {
Log.verbose(getClass(), "Forcing extra inline on " + target.toSourceString());
}
- performInlining(target, inlinee, callGraph);
+ performInlining(target, inlinee, isProcessedConcurrently,
+ callSiteInformation);
}
// Make sure constructor inlining is legal.
assert !target.isClassInitializer();
@@ -376,7 +372,7 @@
if (invoke.isInvokeMethodWithReceiver()) {
// If the invoke has a receiver but the declared method holder is different
// from the computed target holder, inlining requires a downcast of the receiver.
- if (result.target.method.getHolder() != target.method.getHolder()) {
+ if (target.method.getHolder() != invoke.getInvokedMethod().getHolder()) {
downcast = result.target.method.getHolder();
}
}
@@ -384,7 +380,7 @@
// Back up before the invoke instruction.
iterator.previous();
instruction_allowance -= numberOfInstructions(inlinee);
- if (instruction_allowance >= 0 || result.forceInline()) {
+ if (instruction_allowance >= 0 || result.ignoreInstructionBudget()) {
iterator.inlineInvoke(code, inlinee, blockIterator, blocksToRemove, downcast);
}
// If we inlined the invoke from a bridge method, it is no longer a bridge method.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 91f0a61..8b7a05e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -11,10 +11,11 @@
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.ir.code.InvokePolymorphic;
import com.android.tools.r8.ir.code.InvokeStatic;
-import com.android.tools.r8.ir.conversion.CallGraph;
+import com.android.tools.r8.ir.conversion.CallSiteInformation;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.logging.Log;
+import java.util.function.Predicate;
/**
* The InliningOracle contains information needed for when inlining
@@ -26,16 +27,19 @@
private final Inliner inliner;
private final DexEncodedMethod method;
- private final CallGraph callGraph;
+ private final CallSiteInformation callSiteInformation;
+ private final Predicate<DexEncodedMethod> isProcessedConcurrently;
private final InliningInfo info;
InliningOracle(
Inliner inliner,
DexEncodedMethod method,
- CallGraph callGraph) {
+ CallSiteInformation callSiteInformation,
+ Predicate<DexEncodedMethod> isProcessedConcurrently) {
this.inliner = inliner;
this.method = method;
- this.callGraph = callGraph;
+ this.callSiteInformation = callSiteInformation;
+ this.isProcessedConcurrently = isProcessedConcurrently;
info = Log.ENABLED ? new InliningInfo(method) : null;
}
@@ -66,7 +70,7 @@
&& inliner.appInfo.withLiveness().alwaysInline.contains(target)) {
return Reason.ALWAYS;
}
- if (callGraph.hasSingleCallSite(target)) {
+ if (callSiteInformation.hasSingleCallSite(target)) {
return Reason.SINGLE_CALLER;
}
if (isDoubleInliningTarget(target)) {
@@ -91,18 +95,13 @@
private synchronized boolean isDoubleInliningTarget(DexEncodedMethod candidate) {
// 10 is found from measuring.
- return callGraph.hasDoubleCallSite(candidate)
+ return callSiteInformation.hasDoubleCallSite(candidate)
&& candidate.getCode().isDexCode()
&& (candidate.getCode().asDexCode().instructions.length <= 10);
}
private boolean passesInliningConstraints(InvokeMethod invoke, DexEncodedMethod candidate,
Reason reason) {
- if (callGraph.isBreaker(method, candidate)) {
- // Cycle breaker so abort to preserve compilation order.
- return false;
- }
-
if (method == candidate) {
// Cannot handle recursive inlining at this point.
// Force inlined method should never be recursive.
@@ -113,6 +112,13 @@
return false;
}
+ if (reason != Reason.FORCE && isProcessedConcurrently.test(candidate)) {
+ if (info != null) {
+ info.exclude(invoke, "is processed in parallel");
+ }
+ return false;
+ }
+
// Abort inlining attempt if method -> target access is not right.
if (!inliner.hasInliningAccess(method, candidate)) {
if (info != null) {
@@ -176,7 +182,7 @@
}
Reason reason = computeInliningReason(candidate);
- if (!candidate.isInliningCandidate(method, reason == Reason.FORCE, inliner.appInfo)) {
+ if (!candidate.isInliningCandidate(method, reason, inliner.appInfo)) {
// Abort inlining attempt if the single target is not an inlining candidate.
if (info != null) {
info.exclude(invoke, "target is not identified for inlining");
@@ -202,7 +208,7 @@
Reason reason = computeInliningReason(candidate);
// Determine if this should be inlined no matter how big it is.
- if (!candidate.isInliningCandidate(method, reason == Reason.FORCE, inliner.appInfo)) {
+ if (!candidate.isInliningCandidate(method, reason, inliner.appInfo)) {
// Abort inlining attempt if the single target is not an inlining candidate.
if (info != null) {
info.exclude(invoke, "target is not identified for inlining");
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 3857c1f..f6d9c26 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,6 +4,7 @@
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;
@@ -969,7 +970,8 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options) {
+ public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options)
+ throws ApiLevelException {
OutlineSourceCode source = new OutlineSourceCode(outline);
IRBuilder builder = new IRBuilder(encodedMethod, source, options);
return builder.build();
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 44f0759..58bf0bb 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,6 +3,7 @@
// 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,8 +76,10 @@
intArrayType = appInfo.dexItemFactory.createType("[I");
}
- public void run() {
- appInfo.classes().forEach(this::processClasses);
+ public void run() throws ApiLevelException {
+ for (DexProgramClass clazz : appInfo.classes()) {
+ processClasses(clazz);
+ }
if (!switchMaps.isEmpty()) {
appInfo.setExtension(SwitchMapCollector.class, switchMaps);
}
@@ -89,7 +92,7 @@
return switchMaps.get(field);
}
- private void processClasses(DexProgramClass clazz) {
+ private void processClasses(DexProgramClass clazz) throws ApiLevelException {
// 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/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 6cd453b..f4c51ce 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
@@ -197,7 +197,6 @@
}
}
- clearUserInfo();
assert code.isConsistentGraph();
if (Log.ENABLED) {
Log.debug(this.getClass(), toString());
@@ -206,6 +205,7 @@
if (debug) {
computeDebugInfo(blocks);
}
+ clearUserInfo();
clearState();
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
index bd7efce..5fa247e 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
@@ -6,6 +6,7 @@
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;
@@ -16,9 +17,9 @@
import com.android.tools.r8.ir.code.Value;
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;
public abstract class SingleBlockSourceCode implements SourceCode {
@@ -38,7 +39,7 @@
private Value[] paramValues;
// Instruction constructors
- private List<Consumer<IRBuilder>> constructors = new ArrayList<>();
+ private List<ThrowingConsumer<IRBuilder, ApiLevelException>> constructors = new ArrayList<>();
protected SingleBlockSourceCode(DexType receiver, DexProto proto) {
assert proto != null;
@@ -57,7 +58,7 @@
}
}
- protected final void add(Consumer<IRBuilder> constructor) {
+ protected final void add(ThrowingConsumer<IRBuilder, ApiLevelException> constructor) {
constructors.add(constructor);
}
@@ -174,7 +175,8 @@
}
@Override
- public final void buildInstruction(IRBuilder builder, int instructionIndex) {
+ public final void buildInstruction(IRBuilder builder, int instructionIndex)
+ throws ApiLevelException {
constructors.get(instructionIndex).accept(builder);
}
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 3d3f9f1..0de034a 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,6 +4,7 @@
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.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -31,7 +32,8 @@
}
@Override
- public final IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options) {
+ public final IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options)
+ throws ApiLevelException {
return new IRBuilder(encodedMethod, sourceCode, options).build();
}
diff --git a/src/main/java/com/android/tools/r8/naming/DictionaryReader.java b/src/main/java/com/android/tools/r8/naming/DictionaryReader.java
index 146d531..1d05d25 100644
--- a/src/main/java/com/android/tools/r8/naming/DictionaryReader.java
+++ b/src/main/java/com/android/tools/r8/naming/DictionaryReader.java
@@ -9,7 +9,6 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.List;
public class DictionaryReader implements AutoCloseable {
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index a26e135..6a58866 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.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.errors.CompilationError;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index 564e6de..0b683e2 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -64,13 +64,14 @@
private final BufferedReader reader;
+ @Override
public void close() throws IOException {
if (reader != null) {
reader.close();
}
}
- private ProguardMapReader(BufferedReader reader) throws IOException {
+ private ProguardMapReader(BufferedReader reader) {
this.reader = reader;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 153f604..3decec1 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -39,7 +38,7 @@
? new UsagePrinter() : UsagePrinter.DONT_PRINT;
}
- public DexApplication run() throws IOException {
+ public DexApplication run() {
application.timing.begin("Pruning application...");
if (options.debugKeepRules && !options.skipMinification) {
System.out.println(
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 9f3488c..9a87320 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -14,6 +14,7 @@
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.List;
+import java.util.Set;
import java.util.function.Function;
public class InternalOptions {
@@ -197,7 +198,7 @@
public static class TestingOptions {
- public Function<List<DexEncodedMethod>, List<DexEncodedMethod>> irOrdering =
+ public Function<Set<DexEncodedMethod>, Set<DexEncodedMethod>> irOrdering =
Function.identity();
}
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingBiConsumer.java b/src/main/java/com/android/tools/r8/utils/ThrowingBiConsumer.java
new file mode 100644
index 0000000..d7da332
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ThrowingBiConsumer.java
@@ -0,0 +1,15 @@
+package com.android.tools.r8.utils;
+
+import java.util.function.BiConsumer;
+
+/**
+ * Similar to a {@link BiConsumer} but throws a single {@link Throwable}.
+ *
+ * @param <T> the type of the first argument
+ * @param <U> the type of the second argument
+ * @param <E> the type of the {@link Throwable}
+ */
+@FunctionalInterface
+public interface ThrowingBiConsumer<T, U, E extends Throwable> {
+ void accept(T t, U u) throws E;
+}
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingConsumer.java b/src/main/java/com/android/tools/r8/utils/ThrowingConsumer.java
new file mode 100644
index 0000000..8fb8c84
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ThrowingConsumer.java
@@ -0,0 +1,14 @@
+package com.android.tools.r8.utils;
+
+import java.util.function.Consumer;
+
+/**
+ * Similar to a {@link Consumer} but throws a single {@link Throwable}.
+ *
+ * @param <T> the type of the input
+ * @param <E> the type of the {@link Throwable}
+ */
+@FunctionalInterface
+public interface ThrowingConsumer<T, E extends Throwable> {
+ void accept(T t) throws E;
+}
diff --git a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
index 66853cb..61a049e 100644
--- a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
+++ b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
@@ -28,7 +28,7 @@
private static final Path SMALI_DIR = Paths.get(ToolHelper.SMALI_BUILD_DIR);
@Test
- public void UnreachableCode() throws IOException, ExecutionException {
+ public void UnreachableCode() throws IOException, ExecutionException, CompilationException {
String name = "unreachable-code-1";
AndroidApp input = AndroidApp.fromProgramFiles(SMALI_DIR.resolve(name).resolve(name + ".dex"));
ExecutorService executorService = Executors.newSingleThreadExecutor();
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 937f55c..0ca84a1 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -106,9 +106,6 @@
}
void run() throws Throwable {
- if (compilationErrorExpected(testName)) {
- thrown.expect(CompilationError.class);
- }
if (minSdkErrorExpected(testName)) {
thrown.expect(ApiLevelException.class);
}
@@ -154,11 +151,9 @@
abstract void build(Path inputFile, Path out) throws Throwable;
}
- private static List<String> compilationErrorExpected =
- ImmutableList.of("invokepolymorphic-error-due-to-min-sdk");
-
private static List<String> minSdkErrorExpected =
- ImmutableList.of("invokecustom-error-due-to-min-sdk");
+ ImmutableList.of(
+ "invokepolymorphic-error-due-to-min-sdk", "invokecustom-error-due-to-min-sdk");
private static Map<DexVm, List<String>> failsOn =
ImmutableMap.of(
@@ -216,10 +211,6 @@
return failsOn(failsOn, name);
}
- boolean compilationErrorExpected(String testName) {
- return compilationErrorExpected.contains(testName);
- }
-
boolean minSdkErrorExpected(String testName) {
return minSdkErrorExpected.contains(testName);
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 663d6bd..cb8e307 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -523,7 +523,7 @@
DexApplication application,
AppInfoWithSubtyping appInfo,
InternalOptions options)
- throws ProguardRuleParserException, ExecutionException, IOException {
+ throws CompilationException, ExecutionException, IOException {
return R8.optimize(application, appInfo, options);
}
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 bc3d758..75a0275 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
@@ -11,19 +11,23 @@
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.OutputMode;
+import com.beust.jcommander.internal.Lists;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
public class R8GMSCoreDeterministicTest extends GMSCoreCompilationTestBase {
- public List<DexEncodedMethod> shuffle(List<DexEncodedMethod> methods) {
- Collections.shuffle(methods);
- return methods;
+ public Set<DexEncodedMethod> shuffle(Set<DexEncodedMethod> methods) {
+ List<DexEncodedMethod> toShuffle = Lists.newArrayList(methods);
+ Collections.shuffle(toShuffle);
+ return new LinkedHashSet<>(toShuffle);
}
private AndroidApp doRun()
diff --git a/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java b/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
index 50cee1b..cf191de 100644
--- a/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir;
+import com.android.tools.r8.CompilationException;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -31,7 +32,7 @@
* Third block: Return instruction
*
*/
- IRCode simpleCode() {
+ IRCode simpleCode() throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -61,7 +62,7 @@
}
@Test
- public void removeBeforeNext() {
+ public void removeBeforeNext() throws Exception {
IRCode code = simpleCode();
ListIterator<BasicBlock> blocks = code.listIterator();
@@ -70,7 +71,7 @@
}
@Test
- public void removeTwice() {
+ public void removeTwice() throws Exception {
IRCode code = simpleCode();
ListIterator<BasicBlock> blocks = code.listIterator();
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index f4206ea..6fb5db1 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -24,7 +24,7 @@
public class InlineTest extends SmaliTestBase {
- TestApplication codeForMethodReplaceTest(int a, int b) {
+ TestApplication codeForMethodReplaceTest(int a, int b) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
MethodSignature signature = builder.addStaticMethod(
@@ -88,7 +88,7 @@
ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
}
- public void runInlineTest(int a, int b, int expectedA, int expectedB) {
+ public void runInlineTest(int a, int b, int expectedA, int expectedB) throws Exception {
// Run code without inlining.
TestApplication test = codeForMethodReplaceTest(a, b);
String result = test.run();
@@ -116,12 +116,12 @@
}
@Test
- public void inline() {
+ public void inline() throws Exception {
runInlineTest(1, 1, 2, 0);
runInlineTest(1, 2, 3, 1);
}
- TestApplication codeForMethodReplaceReturnVoidTest(int a, int b) {
+ TestApplication codeForMethodReplaceReturnVoidTest(int a, int b) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
MethodSignature signature = builder.addStaticMethod(
@@ -169,7 +169,7 @@
}
@Test
- public void inlineReturnVoid() {
+ public void inlineReturnVoid() throws Exception {
// Run code without inlining.
TestApplication test = codeForMethodReplaceReturnVoidTest(1, 2);
String result = test.run();
@@ -187,7 +187,7 @@
assertEquals(Integer.toString(1), result);
}
- TestApplication codeForMultipleMethodReplaceTest(int a, int b) {
+ TestApplication codeForMultipleMethodReplaceTest(int a, int b) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
MethodSignature signature = builder.addStaticMethod(
@@ -259,7 +259,7 @@
additionalCode, valueNumberGenerator, options);
}
- public void runInlineMultipleTest(int a, int b, int expectedA, int expectedB) {
+ public void runInlineMultipleTest(int a, int b, int expectedA, int expectedB) throws Exception {
// Run code without inlining.
TestApplication test = codeForMultipleMethodReplaceTest(a, b);
String result = test.run();
@@ -304,12 +304,13 @@
}
@Test
- public void inlineMultiple() {
+ public void inlineMultiple() throws Exception {
runInlineMultipleTest(1, 1, 4, 1);
runInlineMultipleTest(1, 2, 7, 8);
}
- TestApplication codeForMethodReplaceTestWithCatchHandler(int a, int b, boolean twoGuards) {
+ TestApplication codeForMethodReplaceTestWithCatchHandler(int a, int b, boolean twoGuards)
+ throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = twoGuards ?
@@ -385,7 +386,7 @@
}
public void runInlineCallerHasCatchHandlersTest(
- int a, int b, boolean twoGuards, int expectedA, int expectedB) {
+ int a, int b, boolean twoGuards, int expectedA, int expectedB) throws Exception {
// Run code without inlining.
TestApplication test = codeForMethodReplaceTestWithCatchHandler(a, b, twoGuards);
String result = test.run();
@@ -413,14 +414,14 @@
}
@Test
- public void inlineCallerHasCatchHandlers() {
+ public void inlineCallerHasCatchHandlers() throws Exception {
runInlineCallerHasCatchHandlersTest(1, 1, false, 2, 0);
runInlineCallerHasCatchHandlersTest(1, 2, false, 3, 1);
runInlineCallerHasCatchHandlersTest(1, 1, true, 2, 0);
runInlineCallerHasCatchHandlersTest(1, 2, true, 3, 1);
}
- TestApplication codeForInlineCanThrow(int a, int b, boolean twoGuards) {
+ TestApplication codeForInlineCanThrow(int a, int b, boolean twoGuards) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = twoGuards ?
@@ -499,7 +500,7 @@
}
public void runInlineCanThrow(
- int a, int b, boolean twoGuards, int expectedA, int expectedB) {
+ int a, int b, boolean twoGuards, int expectedA, int expectedB) throws Exception {
// Run code without inlining.
TestApplication test = codeForInlineCanThrow(a, b, twoGuards);
String result = test.run();
@@ -527,14 +528,14 @@
}
@Test
- public void inlineCanThrow() {
+ public void inlineCanThrow() throws Exception {
runInlineCanThrow(2, 2, false, 1, 1);
runInlineCanThrow(2, 0, false, -2, -1);
runInlineCanThrow(2, 2, true, 1, 1);
runInlineCanThrow(2, 0, true, -2, -1);
}
- private TestApplication codeForInlineAlwaysThrows(boolean twoGuards) {
+ private TestApplication codeForInlineAlwaysThrows(boolean twoGuards) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = twoGuards ?
@@ -611,7 +612,8 @@
ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
}
- private void runInlineAlwaysThrows(boolean twoGuards, int expectedA, int expectedB) {
+ private void runInlineAlwaysThrows(boolean twoGuards, int expectedA, int expectedB)
+ throws Exception {
// Run code without inlining.
TestApplication test = codeForInlineAlwaysThrows(twoGuards);
String result = test.run();
@@ -640,12 +642,12 @@
}
@Test
- public void inlineAlwaysThrows() {
+ public void inlineAlwaysThrows() throws Exception {
runInlineAlwaysThrows(false, -2, -2);
runInlineAlwaysThrows(true, -2, -1);
}
- private TestApplication codeForInlineAlwaysThrowsMultiple(boolean twoGuards) {
+ private TestApplication codeForInlineAlwaysThrowsMultiple(boolean twoGuards) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = twoGuards ?
@@ -732,7 +734,8 @@
application, method, code, additionalCode, valueNumberGenerator, options);
}
- private void runInlineAlwaysThrowsMultiple(boolean twoGuards, int expectedA, int expectedB) {
+ private void runInlineAlwaysThrowsMultiple(boolean twoGuards, int expectedA, int expectedB)
+ throws Exception {
// Run code without inlining.
TestApplication test = codeForInlineAlwaysThrows(twoGuards);
String result = test.run();
@@ -785,13 +788,13 @@
}
@Test
- public void inlineAlwaysThrowsMultiple() {
+ public void inlineAlwaysThrowsMultiple() throws Exception {
runInlineAlwaysThrowsMultiple(false, -2, -2);
runInlineAlwaysThrowsMultiple(true, -2, -1);
}
private TestApplication codeForInlineAlwaysThrowsMultipleWithControlFlow(
- int a, boolean twoGuards) {
+ int a, boolean twoGuards) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = twoGuards ?
@@ -886,7 +889,7 @@
}
private void runInlineAlwaysThrowsMultipleWithControlFlow(
- int a, boolean twoGuards, int expectedA, int expectedB) {
+ int a, boolean twoGuards, int expectedA, int expectedB) throws Exception {
// Run code without inlining.
TestApplication test = codeForInlineAlwaysThrows(twoGuards);
String result = test.run();
@@ -939,7 +942,7 @@
}
@Test
- public void inlineAlwaysThrowsMultipleWithControlFlow() {
+ public void inlineAlwaysThrowsMultipleWithControlFlow() throws Exception {
runInlineAlwaysThrowsMultipleWithControlFlow(0, false, -2, -2);
runInlineAlwaysThrowsMultipleWithControlFlow(0, true, -2, -1);
runInlineAlwaysThrowsMultipleWithControlFlow(1, false, -2, -2);
@@ -948,8 +951,9 @@
runInlineAlwaysThrowsMultipleWithControlFlow(2, true, -2, -1);
}
- private TestApplication codeForInlineWithHandlersCanThrow(int a, int b, int c,
- boolean twoGuards, boolean callerHasCatchAll, boolean inlineeHasCatchAll) {
+ private TestApplication codeForInlineWithHandlersCanThrow(
+ int a, int b, int c, boolean twoGuards, boolean callerHasCatchAll, boolean inlineeHasCatchAll)
+ throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = "";
@@ -1122,7 +1126,7 @@
private void runInlineWithHandlersCanThrow(int a, int b, int c,
boolean twoGuards, boolean callerHasCatchAll, boolean inlineeHasCatchAll,
- int expectedA, int expectedB) {
+ int expectedA, int expectedB) throws Exception {
// Run code without inlining.
TestApplication test = codeForInlineWithHandlersCanThrow(
a, b, c, twoGuards, callerHasCatchAll, inlineeHasCatchAll);
@@ -1153,7 +1157,7 @@
}
@Test
- public void inlineCanWithHandlersThrow() {
+ public void inlineCanWithHandlersThrow() throws Exception {
// The base generated code will be:
//
// int method(int a, int b, int c) {
diff --git a/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java b/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java
index 1e35475..b9eef9c 100644
--- a/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java
@@ -32,7 +32,7 @@
* Third block: Return instruction
*
*/
- IRCode simpleCode() {
+ IRCode simpleCode() throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -62,7 +62,7 @@
}
@Test
- public void removeBeforeNext() {
+ public void removeBeforeNext() throws Exception {
IRCode code = simpleCode();
ListIterator<BasicBlock> blocks = code.listIterator();
@@ -72,7 +72,7 @@
}
@Test
- public void removeTwice() {
+ public void removeTwice() throws Exception {
IRCode code = simpleCode();
ListIterator<BasicBlock> blocks = code.listIterator();
diff --git a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
index 90e2089..04a55b5 100644
--- a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
+++ b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
@@ -29,7 +29,7 @@
public class SplitBlockTest extends SmaliTestBase {
- TestApplication codeWithoutCatchHandlers() {
+ TestApplication codeWithoutCatchHandlers() throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -68,7 +68,7 @@
}
@Test
- public void noCatchHandlers() {
+ public void noCatchHandlers() throws Exception {
final int initialBlockCount = 1;
final int argumentInstructions = 2;
final int firstBlockInstructions = 6;
@@ -102,7 +102,7 @@
}
@Test
- public void noCatchHandlersSplitThree() {
+ public void noCatchHandlersSplitThree() throws Exception {
final int initialBlockCount = 1;
final int argumentInstructions = 2;
final int firstBlockInstructions = 6;
@@ -136,7 +136,7 @@
}
}
- TestApplication codeWithCatchHandlers(boolean shouldThrow, boolean twoGuards) {
+ TestApplication codeWithCatchHandlers(boolean shouldThrow, boolean twoGuards) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = twoGuards ?
@@ -192,7 +192,7 @@
assertEquals(throwing, block.hasCatchHandlers());
}
- public void runCatchHandlerTest(boolean codeThrows, boolean twoGuards) {
+ public void runCatchHandlerTest(boolean codeThrows, boolean twoGuards) throws Exception {
final int secondBlockInstructions = 4;
final int initialBlockCount = 5;
// Try split between all instructions in second block.
@@ -223,14 +223,15 @@
}
@Test
- public void catchHandlers() {
+ public void catchHandlers() throws Exception {
runCatchHandlerTest(false, false);
runCatchHandlerTest(true, false);
runCatchHandlerTest(false, true);
runCatchHandlerTest(true, true);
}
- public void runCatchHandlerSplitThreeTest(boolean codeThrows, boolean twoGuards) {
+ public void runCatchHandlerSplitThreeTest(boolean codeThrows, boolean twoGuards)
+ throws Exception {
final int secondBlockInstructions = 4;
final int initialBlockCount = 5;
// Try split out all instructions in second block.
@@ -262,14 +263,14 @@
}
@Test
- public void catchHandlersSplitThree() {
+ public void catchHandlersSplitThree() throws Exception {
runCatchHandlerSplitThreeTest(false, false);
runCatchHandlerSplitThreeTest(true, false);
runCatchHandlerSplitThreeTest(false, true);
runCatchHandlerSplitThreeTest(true, true);
}
- TestApplication codeWithIf(boolean hitTrueBranch) {
+ TestApplication codeWithIf(boolean hitTrueBranch) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -309,7 +310,7 @@
return new TestApplication(application, method, code, valueNumberGenerator, options);
}
- public void runWithIfTest(boolean hitTrueBranch) {
+ public void runWithIfTest(boolean hitTrueBranch) throws Exception {
final int initialBlockCount = 4;
final int argumentInstructions = 2;
final int firstBlockInstructions = 3;
@@ -343,12 +344,12 @@
}
@Test
- public void withIf() {
+ public void withIf() throws Exception {
runWithIfTest(false);
runWithIfTest(true);
}
- public void splitBeforeReturn(boolean hitTrueBranch) {
+ public void splitBeforeReturn(boolean hitTrueBranch) throws Exception {
TestApplication test = codeWithIf(hitTrueBranch);
IRCode code = test.code;
// Locate the exit block and split before the return (the first instruction in the block).
@@ -375,12 +376,12 @@
}
@Test
- public void splitBeforeReturn() {
+ public void splitBeforeReturn() throws Exception {
splitBeforeReturn(false);
splitBeforeReturn(true);
}
- TestApplication codeWithSwitch(boolean hitCase) {
+ TestApplication codeWithSwitch(boolean hitCase) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -428,7 +429,7 @@
return new TestApplication(application, method, code, valueNumberGenerator, options);
}
- public void runWithSwitchTest(boolean hitCase) {
+ public void runWithSwitchTest(boolean hitCase) throws Exception {
final int initialBlockCount = 5;
final int argumentInstructions = 1;
final int firstBlockInstructions = 2;
@@ -462,7 +463,7 @@
}
@Test
- public void withSwitch() {
+ public void withSwitch() throws Exception {
runWithSwitchTest(false);
runWithSwitchTest(true);
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
index 04d84e4..1573b34 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -5,6 +5,7 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.CompilationException;
import com.android.tools.r8.R8;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -131,7 +132,7 @@
}
protected static DexApplication process(DexApplication app, InternalOptions options)
- throws IOException, ProguardRuleParserException, ExecutionException {
+ throws IOException, CompilationException, ExecutionException {
return ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), options);
}
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/Regress65007724.java b/src/test/java/com/android/tools/r8/jasmin/Regress65007724.java
new file mode 100644
index 0000000..1eb0586
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/jasmin/Regress65007724.java
@@ -0,0 +1,35 @@
+// 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.jasmin;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class Regress65007724 extends JasminTestBase {
+ @Test
+ public void testThat16BitsIndexAreAllowed() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+
+ for (int i = 0; i < 35000; i++) {
+ builder.addClass("C" + i);
+ }
+
+ JasminBuilder.ClassBuilder clazz = builder.addClass("Test");
+
+ clazz.addStaticField("f", "LC34000;", null);
+
+ clazz.addMainMethod(
+ ".limit stack 2",
+ ".limit locals 1",
+ "getstatic java/lang/System/out Ljava/io/PrintStream;",
+ "ldc \"Hello World!\"",
+ "invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
+ "return");
+
+ String expected = runOnJava(builder, clazz.name);
+ String artResult = runOnArtD8(builder, clazz.name);
+ assertEquals(expected, artResult);
+ }
+}
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 d5f9c6a..601ca23 100644
--- a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
+++ b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
@@ -60,7 +60,7 @@
}
void compileWithR8(Path inputPath, Path outputPath, Path keepRulesPath)
- throws IOException, CompilationException, ExecutionException, ProguardRuleParserException {
+ throws IOException, CompilationException, ProguardRuleParserException {
AndroidApp androidApp =
R8.run(
R8Command.builder()
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 d7d30d4..619f808 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -538,13 +538,13 @@
}
public static AndroidApp generateApplication(List<String> classes, int minApi, int methodCount)
- throws IOException, ExecutionException {
+ throws IOException, ExecutionException, CompilationException {
return generateApplication(classes, minApi, false, methodCount);
}
private static AndroidApp generateApplication(
List<String> classes, int minApi, boolean intermediate, int methodCount)
- throws IOException, ExecutionException {
+ throws IOException, ExecutionException, CompilationException {
Timing timing = new Timing("MainDexListTests");
InternalOptions options = new InternalOptions();
options.minApiLevel = minApi;
diff --git a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
index ca30f76..909f574 100644
--- a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
+++ b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
@@ -26,7 +26,7 @@
public class CatchSuccessorFallthroughTest extends SmaliTestBase {
@Test
- public void catchSuccessorFallthroughTest() {
+ public void catchSuccessorFallthroughTest() throws Exception {
SmaliBuilder builder = new SmaliBuilder("Test");
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 0322407..f35dd21 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.CompilationException;
import com.android.tools.r8.R8;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
@@ -431,7 +432,7 @@
protected DexApplication processApplication(DexApplication application, InternalOptions options) {
try {
return ToolHelper.optimizeWithR8(application, new AppInfoWithSubtyping(application), options);
- } catch (IOException | ProguardRuleParserException | ExecutionException e) {
+ } catch (IOException | CompilationException | ExecutionException e) {
throw new RuntimeException(e);
}
}