Merge "Skip emitting initial advance pc of zero"
diff --git a/build.gradle b/build.gradle
index e6432e4..580bcaf 100644
--- a/build.gradle
+++ b/build.gradle
@@ -478,13 +478,16 @@
}
}
-static configureRelocations(ShadowJar task) {
+static mergeServiceFiles(ShadowJar task) {
// Everything under META-INF is not included by default.
// Should include before 'relocate' so that the service file path and its content
// are properly relocated as well.
task.mergeServiceFiles {
include 'META-INF/services/*'
}
+}
+
+static configureRelocations(ShadowJar task) {
task.relocate('com.google.common', 'com.android.tools.r8.com.google.common')
task.relocate('com.google.gson', 'com.android.tools.r8.com.google.gson')
task.relocate('com.google.thirdparty', 'com.android.tools.r8.com.google.thirdparty')
@@ -500,7 +503,10 @@
task repackageDeps(type: ShadowJar) {
configurations = [project.configurations.compile]
- configureRelocations(it)
+ mergeServiceFiles(it)
+ if (!project.hasProperty('lib_no_relocate')) {
+ configureRelocations(it)
+ }
exclude { it.getRelativePath().getPathString() == "module-info.class" }
exclude { it.getRelativePath().getPathString().startsWith("META-INF/maven/") }
baseName 'deps'
@@ -508,7 +514,10 @@
task repackageSources(type: ShadowJar) {
from sourceSets.main.output
- configureRelocations(it)
+ mergeServiceFiles(it)
+ if (!project.hasProperty('lib_no_relocate')) {
+ configureRelocations(it)
+ }
baseName 'sources'
}
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 297d6df..34a3a93 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.Reporter;
import java.nio.file.Path;
@@ -36,7 +35,7 @@
programConsumer = null;
mode = null;
minApiLevel = 0;
- reporter = new Reporter(new DefaultDiagnosticsHandler());
+ reporter = new Reporter();
enableDesugaring = true;
optimizeMultidexForLinearAlloc = false;
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 964f699..2441034 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -38,20 +37,20 @@
}
}
- private static class DefaultD8DiagnosticsHandler extends DefaultDiagnosticsHandler {
+ private static class DefaultD8DiagnosticsHandler implements DiagnosticsHandler {
@Override
public void error(Diagnostic error) {
if (error instanceof DexFileOverflowDiagnostic) {
DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error;
if (!overflowDiagnostic.hasMainDexSpecification()) {
- super.error(
+ DiagnosticsHandler.super.error(
new StringDiagnostic(
overflowDiagnostic.getDiagnosticMessage() + ". Try supplying a main-dex list"));
return;
}
}
- super.error(error);
+ DiagnosticsHandler.super.error(error);
}
}
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index 6fd04b6..fd85c25 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -26,6 +26,7 @@
import java.util.Collection;
import java.util.concurrent.ExecutionException;
+@Keep
public class ExtractMarker {
public static class VdexOrigin extends Origin {
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 43989ff..d28e045 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
@@ -28,6 +29,7 @@
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
+@Keep
public class GenerateMainDexList {
private final Timing timing = new Timing("maindex");
private final InternalOptions options;
@@ -41,10 +43,11 @@
try {
DexApplication application =
new ApplicationReader(app, options, timing).read(executor).toDirect();
- AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
+ AppView<? extends AppInfoWithSubtyping> appView =
+ new AppView<>(new AppInfoWithSubtyping(application), GraphLense.getIdentityLense());
RootSet mainDexRootSet =
- new RootSetBuilder(appInfo, application, options.mainDexKeepRules, options).run(executor);
- Enqueuer enqueuer = new Enqueuer(appInfo, GraphLense.getIdentityLense(), options, true);
+ new RootSetBuilder(appView, application, options.mainDexKeepRules, options).run(executor);
+ Enqueuer enqueuer = new Enqueuer(appView, options, true);
AppInfoWithLiveness mainDexAppInfo = enqueuer.traceMainDex(mainDexRootSet, executor, timing);
// LiveTypes is the result.
Set<DexType> mainDexClasses =
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java b/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
index 2d06da8..ec7bc53 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.shaking.ProguardConfigurationSourceFile;
import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -199,7 +198,7 @@
this.factory = new DexItemFactory();
this.mainDexKeepRules = ImmutableList.of();
this.mainDexListConsumer = null;
- this.reporter = new Reporter(new DefaultDiagnosticsHandler());
+ this.reporter = new Reporter();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/PrintSeeds.java b/src/main/java/com/android/tools/r8/PrintSeeds.java
index 78cb75a..4c52b53 100644
--- a/src/main/java/com/android/tools/r8/PrintSeeds.java
+++ b/src/main/java/com/android/tools/r8/PrintSeeds.java
@@ -5,9 +5,11 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.shaking.RootSetBuilder;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
import com.android.tools.r8.utils.ExceptionUtils;
@@ -76,21 +78,21 @@
private static void run(
R8Command command, Set<String> descriptors, InternalOptions options, ExecutorService executor)
throws IOException {
+ assert !options.forceProguardCompatibility;
Timing timing = new Timing("PrintSeeds");
try {
DexApplication application =
new ApplicationReader(command.getInputApp(), options, timing).read(executor).toDirect();
- AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
+ AppView<? extends AppInfoWithSubtyping> appView =
+ new AppView<>(new AppInfoWithSubtyping(application), GraphLense.getIdentityLense());
RootSet rootSet =
new RootSetBuilder(
- appInfo, application, options.proguardConfiguration.getRules(), options)
+ appView, application, options.proguardConfiguration.getRules(), options)
.run(executor);
- Enqueuer enqueuer = new Enqueuer(appInfo, GraphLense.getIdentityLense(), options, false);
- appInfo = enqueuer.traceApplication(rootSet, executor, timing);
+ Enqueuer enqueuer = new Enqueuer(appView, options);
+ AppInfoWithLiveness appInfo = enqueuer.traceApplication(rootSet, executor, timing);
RootSetBuilder.writeSeeds(
- appInfo.withLiveness(),
- System.out,
- type -> descriptors.contains(type.toDescriptorString()));
+ appInfo, System.out, type -> descriptors.contains(type.toDescriptorString()));
} catch (ExecutionException e) {
throw R8.unwrapExecutionException(e);
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 8be6306..ec863ee 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -275,24 +275,15 @@
// kotlin metadata annotation is removed.
computeKotlinInfoForProgramClasses(application, appView.appInfo());
- final ProguardConfiguration.Builder compatibility =
+ ProguardConfiguration.Builder compatibility =
ProguardConfiguration.builder(application.dexItemFactory, options.reporter);
rootSet =
new RootSetBuilder(
- appView.appInfo(),
- application,
- options.proguardConfiguration.getRules(),
- options)
+ appView, application, options.proguardConfiguration.getRules(), options)
.run(executorService);
- Enqueuer enqueuer =
- new Enqueuer(
- appView.appInfo(),
- appView.graphLense(),
- options,
- options.forceProguardCompatibility,
- compatibility);
+ Enqueuer enqueuer = new Enqueuer(appView, options, compatibility);
appView.setAppInfo(enqueuer.traceApplication(rootSet, executorService, timing));
if (options.proguardConfiguration.isPrintSeeds()) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
@@ -416,10 +407,10 @@
if (!options.mainDexKeepRules.isEmpty()) {
appView.setAppInfo(new AppInfoWithSubtyping(application));
- Enqueuer enqueuer = new Enqueuer(appView.appInfo(), appView.graphLense(), options, true);
+ Enqueuer enqueuer = new Enqueuer(appView, options, true);
// Lets find classes which may have code executed before secondary dex files installation.
RootSet mainDexRootSet =
- new RootSetBuilder(appView.appInfo(), application, options.mainDexKeepRules, options)
+ new RootSetBuilder(appView, application, options.mainDexKeepRules, options)
.run(executorService);
AppInfoWithLiveness mainDexAppInfo =
enqueuer.traceMainDex(mainDexRootSet, executorService, timing);
@@ -448,12 +439,7 @@
if (options.enableTreeShaking || options.enableMinification) {
timing.begin("Post optimization code stripping");
try {
- Enqueuer enqueuer =
- new Enqueuer(
- appView.appInfo(),
- appView.graphLense(),
- options,
- options.forceProguardCompatibility);
+ Enqueuer enqueuer = new Enqueuer(appView, options);
appView.setAppInfo(enqueuer.traceApplication(rootSet, executorService, timing));
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 78a9d3f..7b24770 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.shaking.ProguardConfigurationSourceFile;
import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -58,21 +57,21 @@
@Keep
public static class Builder extends BaseCompilerCommand.Builder<R8Command, Builder> {
- private static class DefaultR8DiagnosticsHandler extends DefaultDiagnosticsHandler {
+ private static class DefaultR8DiagnosticsHandler implements DiagnosticsHandler {
@Override
public void error(Diagnostic error) {
if (error instanceof DexFileOverflowDiagnostic) {
DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error;
if (!overflowDiagnostic.hasMainDexSpecification()) {
- super.error(
+ DiagnosticsHandler.super.error(
new StringDiagnostic(
overflowDiagnostic.getDiagnosticMessage()
+ ". Try supplying a main-dex list or main-dex rules"));
return;
}
}
- super.error(error);
+ DiagnosticsHandler.super.error(error);
}
}
@@ -651,6 +650,9 @@
assert internal.enableVerticalClassMerging || !proguardConfiguration.isOptimizing();
if (internal.debug) {
+ internal.proguardConfiguration.getKeepAttributes().lineNumberTable = true;
+ internal.proguardConfiguration.getKeepAttributes().localVariableTable = true;
+ internal.proguardConfiguration.getKeepAttributes().localVariableTypeTable = true;
// TODO(zerny): Should we support inlining in debug mode? b/62937285
internal.enableInlining = false;
internal.enableClassInlining = false;
diff --git a/src/main/java/com/android/tools/r8/ReadKeepFile.java b/src/main/java/com/android/tools/r8/ReadKeepFile.java
index 07d5044..c953c8d 100644
--- a/src/main/java/com/android/tools/r8/ReadKeepFile.java
+++ b/src/main/java/com/android/tools/r8/ReadKeepFile.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.Timing;
import java.nio.file.Paths;
@@ -22,8 +21,7 @@
private void readProguardKeepFile(String fileName) {
System.out.println(" - reading " + fileName);
timing.begin("Reading " + fileName);
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()))
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter())
.parse(Paths.get(fileName));
timing.end();
}
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 0d4e79d..3dbaa56 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.4.0-dev";
+ public static final String LABEL = "1.4.2-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/cf/FixedLocalValue.java b/src/main/java/com/android/tools/r8/cf/FixedLocalValue.java
index b9be068..d703c88 100644
--- a/src/main/java/com/android/tools/r8/cf/FixedLocalValue.java
+++ b/src/main/java/com/android/tools/r8/cf/FixedLocalValue.java
@@ -18,7 +18,7 @@
private final Phi phi;
public FixedLocalValue(Phi phi) {
- super(phi.getNumber(), phi.outType(), phi.getLocalInfo());
+ super(phi.getNumber(), phi.getTypeLattice(), phi.getLocalInfo());
this.phi = phi;
}
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
index 08af875..d640a30 100644
--- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -68,7 +68,7 @@
}
private TypeLatticeElement getLatticeElement(DexType type) {
- return TypeLatticeElement.fromDexType(appInfo, type, true);
+ return TypeLatticeElement.fromDexType(type, appInfo, true);
}
public Map<Value, DexType> computeVerificationTypes() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index c24490c..2ea0593 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -124,6 +124,6 @@
@Override
public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
- builder.addConst(type, state.push(type).register, value);
+ builder.addConst(type.toTypeLattice(), state.push(type).register, value);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/CheckCast.java b/src/main/java/com/android/tools/r8/code/CheckCast.java
index 9416a7b..57151fa 100644
--- a/src/main/java/com/android/tools/r8/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/code/CheckCast.java
@@ -38,6 +38,11 @@
}
@Override
+ public boolean isCheckCast() {
+ return true;
+ }
+
+ @Override
public void registerUse(UseRegistry registry) {
registry.registerCheckCast(getType());
}
diff --git a/src/main/java/com/android/tools/r8/code/Const.java b/src/main/java/com/android/tools/r8/code/Const.java
index 1d8313d..48c1aa9 100644
--- a/src/main/java/com/android/tools/r8/code/Const.java
+++ b/src/main/java/com/android/tools/r8/code/Const.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.SingleConstant;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
@@ -58,7 +58,8 @@
@Override
public void buildIR(IRBuilder builder) {
int value = decodedValue();
- ValueType type = value == 0 ? ValueType.INT_OR_FLOAT_OR_NULL : ValueType.INT_OR_FLOAT;
- builder.addConst(type, AA, value);
+ TypeLatticeElement typeLattice =
+ value == 0 ? TypeLatticeElement.BOTTOM : TypeLatticeElement.SINGLE;
+ builder.addConst(typeLattice, AA, value);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Const16.java b/src/main/java/com/android/tools/r8/code/Const16.java
index 24dae68..c4d46e2 100644
--- a/src/main/java/com/android/tools/r8/code/Const16.java
+++ b/src/main/java/com/android/tools/r8/code/Const16.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.SingleConstant;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
@@ -52,7 +52,8 @@
@Override
public void buildIR(IRBuilder builder) {
int value = decodedValue();
- ValueType type = value == 0 ? ValueType.INT_OR_FLOAT_OR_NULL : ValueType.INT_OR_FLOAT;
- builder.addConst(type, AA, value);
+ TypeLatticeElement typeLattice =
+ value == 0 ? TypeLatticeElement.BOTTOM : TypeLatticeElement.SINGLE;
+ builder.addConst(typeLattice, AA, value);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Const4.java b/src/main/java/com/android/tools/r8/code/Const4.java
index 497a9ed..edfcb28 100644
--- a/src/main/java/com/android/tools/r8/code/Const4.java
+++ b/src/main/java/com/android/tools/r8/code/Const4.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.SingleConstant;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
@@ -58,7 +58,8 @@
@Override
public void buildIR(IRBuilder builder) {
int value = decodedValue();
- ValueType type = value == 0 ? ValueType.INT_OR_FLOAT_OR_NULL : ValueType.INT_OR_FLOAT;
- builder.addConst(type, A, value);
+ TypeLatticeElement typeLattice =
+ value == 0 ? TypeLatticeElement.BOTTOM : TypeLatticeElement.SINGLE;
+ builder.addConst(typeLattice, A, value);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstHigh16.java b/src/main/java/com/android/tools/r8/code/ConstHigh16.java
index ecaf61f..70e31c8 100644
--- a/src/main/java/com/android/tools/r8/code/ConstHigh16.java
+++ b/src/main/java/com/android/tools/r8/code/ConstHigh16.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.SingleConstant;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
@@ -58,7 +58,8 @@
@Override
public void buildIR(IRBuilder builder) {
int value = decodedValue();
- ValueType type = value == 0 ? ValueType.INT_OR_FLOAT_OR_NULL : ValueType.INT_OR_FLOAT;
- builder.addConst(type, AA, value);
+ TypeLatticeElement typeLattice =
+ value == 0 ? TypeLatticeElement.BOTTOM : TypeLatticeElement.SINGLE;
+ builder.addConst(typeLattice, AA, value);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstString.java b/src/main/java/com/android/tools/r8/code/ConstString.java
index d165de5..ed7847a 100644
--- a/src/main/java/com/android/tools/r8/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/code/ConstString.java
@@ -45,6 +45,11 @@
}
@Override
+ public boolean isConstString() {
+ return true;
+ }
+
+ @Override
public String toString(ClassNameMapper naming) {
return formatString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide.java b/src/main/java/com/android/tools/r8/code/ConstWide.java
index 509b00b..1820172 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWide.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
@Override
public void buildIR(IRBuilder builder) {
- builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
+ builder.addConst(TypeLatticeElement.WIDE, AA, decodedValue());
}
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide16.java b/src/main/java/com/android/tools/r8/code/ConstWide16.java
index 4b74eb4..ad7e84f 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide16.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWide16.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
@Override
public void buildIR(IRBuilder builder) {
- builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
+ builder.addConst(TypeLatticeElement.WIDE, AA, decodedValue());
}
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide32.java b/src/main/java/com/android/tools/r8/code/ConstWide32.java
index f09fd14..0b75213 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide32.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWide32.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
@Override
public void buildIR(IRBuilder builder) {
- builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
+ builder.addConst(TypeLatticeElement.WIDE, AA, decodedValue());
}
}
diff --git a/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java b/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
index 762e2ee..e139b35 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
+++ b/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
-import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -57,6 +57,6 @@
@Override
public void buildIR(IRBuilder builder) {
- builder.addConst(ValueType.LONG_OR_DOUBLE, AA, decodedValue());
+ builder.addConst(TypeLatticeElement.WIDE, AA, decodedValue());
}
}
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 c8b5154..fbb93ca 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -122,6 +122,14 @@
this.offset = offset;
}
+ public boolean isCheckCast() {
+ return false;
+ }
+
+ public boolean isConstString() {
+ return false;
+ }
+
public boolean isSimpleNop() {
return !isPayload() && this instanceof Nop;
}
diff --git a/src/main/java/com/android/tools/r8/code/MoveType.java b/src/main/java/com/android/tools/r8/code/MoveType.java
index a9ff6e0..ac0af87 100644
--- a/src/main/java/com/android/tools/r8/code/MoveType.java
+++ b/src/main/java/com/android/tools/r8/code/MoveType.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.ValueType;
public enum MoveType {
@@ -29,14 +30,14 @@
}
}
- public ValueType toValueType() {
+ public TypeLatticeElement toTypeLattice() {
switch (this) {
case SINGLE:
- return ValueType.INT_OR_FLOAT;
+ return TypeLatticeElement.SINGLE;
case WIDE:
- return ValueType.LONG_OR_DOUBLE;
+ return TypeLatticeElement.WIDE;
case OBJECT:
- return ValueType.OBJECT;
+ return TypeLatticeElement.REFERENCE;
default:
throw new Unreachable("Unexpected move type: " + this);
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index d762646..657e029 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -59,7 +59,6 @@
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.Pair;
import com.google.common.io.ByteStreams;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
@@ -97,8 +96,9 @@
}
private static DexSection[] parseMapFrom(DexReader dexReader) {
- DexParser dexParser = new DexParser(dexReader,
- ClassKind.PROGRAM, new DexItemFactory(), new DefaultDiagnosticsHandler());
+ DexParser dexParser =
+ new DexParser(
+ dexReader, ClassKind.PROGRAM, new DexItemFactory(), new DiagnosticsHandler() {});
return dexParser.dexSections;
}
diff --git a/src/main/java/com/android/tools/r8/dexfilemerger/DexFileMerger.java b/src/main/java/com/android/tools/r8/dexfilemerger/DexFileMerger.java
index b5db1ae..7cbf816 100644
--- a/src/main/java/com/android/tools/r8/dexfilemerger/DexFileMerger.java
+++ b/src/main/java/com/android/tools/r8/dexfilemerger/DexFileMerger.java
@@ -73,6 +73,22 @@
}
throw new AssertionError("Unknown: " + this);
}
+
+ public static MultidexStrategy parse(String value) {
+ switch (value) {
+ case "off":
+ return OFF;
+ case "given_shard":
+ return GIVEN_SHARD;
+ case "minimal":
+ return MINIMAL;
+ case "best_effort":
+ return BEST_EFFORT;
+ default:
+ throw new RuntimeException(
+ "Multidex argument must be either 'off', 'given_shard', 'minimal' or 'best_effort'.");
+ }
+ }
}
private static class Options {
@@ -129,7 +145,7 @@
}
string = OptionsParsing.tryParseSingle(context, "--multidex", null);
if (string != null) {
- options.multidexMode = MultidexStrategy.valueOf(string.toUpperCase());
+ options.multidexMode = MultidexStrategy.parse(string);
continue;
}
string = OptionsParsing.tryParseSingle(context, "--main-dex-list", null);
diff --git a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java b/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
index 321482e..f83012f 100644
--- a/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
+++ b/src/main/java/com/android/tools/r8/dexsplitter/DexSplitter.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.Keep;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.AbortException;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.FeatureClassMapping;
@@ -87,7 +86,7 @@
@Keep
public static final class Options {
- private final DiagnosticsHandler diagnosticsHandler = new DefaultDiagnosticsHandler();
+ private final DiagnosticsHandler diagnosticsHandler = new DiagnosticsHandler() {};
private List<String> inputArchives = new ArrayList<>();
private List<FeatureJar> featureJars = new ArrayList<>();
private List<String> baseJars = new ArrayList<>();
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 3df31fd..22790b4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -412,6 +412,10 @@
return null;
}
+ public boolean isExternalizable(AppInfo appInfo) {
+ return type.implementedInterfaces(appInfo).contains(appInfo.dexItemFactory.externalizableType);
+ }
+
public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
return Arrays.stream(staticFields())
.anyMatch(field -> !field.getStaticValue().mayTriggerAllocation());
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 3d83104..f2cc53f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -301,10 +301,21 @@
}
public IRCode buildInliningIRForTesting(
- InternalOptions options, ValueNumberGenerator valueNumberGenerator) {
+ InternalOptions options, ValueNumberGenerator valueNumberGenerator, AppInfo appInfo) {
checkIfObsolete();
return buildInliningIR(
- null, GraphLense.getIdentityLense(), options, valueNumberGenerator, null, Origin.unknown());
+ appInfo,
+ GraphLense.getIdentityLense(),
+ options,
+ valueNumberGenerator,
+ null,
+ Origin.unknown());
+ }
+
+ public IRCode buildInliningIRForTesting(
+ InternalOptions options, ValueNumberGenerator valueNumberGenerator) {
+ checkIfObsolete();
+ return buildInliningIRForTesting(options, valueNumberGenerator, null);
}
public IRCode buildInliningIR(
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index b02222f..90a098a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -70,12 +70,14 @@
public static final DexType nullValueType = new DexType(new DexString("NULL"));
public static final DexString unknownTypeName = new DexString("UNKNOWN");
+ public static final DexType unknownType = new DexType(unknownTypeName);
private static final IdentityHashMap<DexItem, DexItem> internalSentinels =
new IdentityHashMap<>(
ImmutableMap.of(
catchAllType, catchAllType,
nullValueType, nullValueType,
+ unknownType, unknownType,
unknownTypeName, unknownTypeName));
public DexItemFactory() {
@@ -254,6 +256,7 @@
public final DexType callSiteType = createType("Ljava/lang/invoke/CallSite;");
public final DexType lookupType = createType("Ljava/lang/invoke/MethodHandles$Lookup;");
public final DexType serializableType = createType("Ljava/io/Serializable;");
+ public final DexType externalizableType = createType("Ljava/io/Externalizable;");
public final DexType comparableType = createType("Ljava/lang/Comparable;");
public final DexMethod metafactoryMethod =
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index fe63f46..138e07e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -37,6 +37,9 @@
*/
private Set<DexType> directSubtypes = NO_DIRECT_SUBTYPE;
+ // Caching what interfaces this type is implementing. This includes super-interface hierarchy.
+ private Set<DexType> implementedInterfaces;
+
DexType(DexString descriptor) {
assert !descriptor.toString().contains(".");
this.descriptor = descriptor;
@@ -234,9 +237,12 @@
* @return a set of interfaces of {@link DexType}.
*/
public Set<DexType> implementedInterfaces(AppInfo appInfo) {
- Set<DexType> interfaces = Sets.newIdentityHashSet();
- implementedInterfaces(appInfo, interfaces);
- return interfaces;
+ if (implementedInterfaces == null) {
+ Set<DexType> interfaces = Sets.newIdentityHashSet();
+ implementedInterfaces(appInfo, interfaces);
+ implementedInterfaces = interfaces;
+ }
+ return implementedInterfaces;
}
private void implementedInterfaces(AppInfo appInfo, Set<DexType> interfaces) {
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 400e5ba..0f0b5e5 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import static org.objectweb.asm.ClassReader.SKIP_CODE;
+import static org.objectweb.asm.ClassReader.SKIP_DEBUG;
import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
import static org.objectweb.asm.Opcodes.ACC_DEPRECATED;
import static org.objectweb.asm.Opcodes.ASM6;
@@ -27,6 +28,7 @@
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.FieldSignatureEquivalence;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
@@ -93,9 +95,18 @@
input.reset();
ClassReader reader = new ClassReader(input);
+
+ int parsingOptions = SKIP_FRAMES | SKIP_CODE;
+
+ // If the source-file and source-debug-extension attributes are not kept we can skip all debug
+ // related attributes when parsing the class structure.
+ ProguardKeepAttributes keep = application.options.proguardConfiguration.getKeepAttributes();
+ if (!keep.sourceFile && !keep.sourceDebugExtension) {
+ parsingOptions |= SKIP_DEBUG;
+ }
reader.accept(
new CreateDexClassVisitor(origin, classKind, reader.b, application, classConsumer),
- SKIP_FRAMES | SKIP_CODE);
+ parsingOptions);
}
private static int cleanAccessFlags(int access) {
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 b978408..0668d05 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.io.PrintWriter;
@@ -163,7 +164,7 @@
InternalOptions options,
ValueNumberGenerator generator,
Position callerPosition) {
- if (!options.debug || options.testing.removeLocalsTable) {
+ if (!options.debug || !options.proguardConfiguration.getKeepAttributes().localVariableTable) {
node.localVariables.clear();
}
JarSourceCode source =
@@ -241,9 +242,16 @@
}
private void parseCode(ReparseContext context, boolean useJsrInliner) {
+ // If the keep attributes do not specify keeping LocalVariableTable, LocalVariableTypeTable or
+ // LineNumberTable, then we can skip parsing all the debug related attributes during code read.
+ int parsingOptions = ClassReader.SKIP_FRAMES;
+ ProguardKeepAttributes keep = application.options.proguardConfiguration.getKeepAttributes();
+ if (!keep.localVariableTable && !keep.localVariableTypeTable && !keep.lineNumberTable) {
+ parsingOptions |= ClassReader.SKIP_DEBUG;
+ }
SecondVisitor classVisitor = new SecondVisitor(createCodeLocator(context), useJsrInliner);
try {
- new ClassReader(context.classCache).accept(classVisitor, ClassReader.SKIP_FRAMES);
+ new ClassReader(context.classCache).accept(classVisitor, parsingOptions);
} catch (Exception exception) {
throw new CompilationError(
"Unable to parse method `" + method.toSourceString() + "`", exception);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
index c8f2b8c..6b368b3 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
@@ -31,7 +31,7 @@
}
@Override
- TypeLatticeElement asNullable() {
+ public TypeLatticeElement asNullable() {
return isNullable() ? this : new ArrayTypeLatticeElement(type, true);
}
@@ -52,7 +52,7 @@
@Override
public TypeLatticeElement arrayGet(AppInfo appInfo) {
- return fromDexType(appInfo, getArrayElementType(appInfo.dexItemFactory), true);
+ return fromDexType(getArrayElementType(appInfo.dexItemFactory), appInfo, true);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java
index 81b4488..dba0a2a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java
@@ -14,11 +14,11 @@
}
@Override
- TypeLatticeElement asNullable() {
+ public TypeLatticeElement asNullable() {
return this;
}
- public static BottomTypeLatticeElement getInstance() {
+ static BottomTypeLatticeElement getInstance() {
return INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java
index 3efc915..de75d5f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.analysis.type;
-import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexType;
import java.util.Set;
@@ -28,7 +27,7 @@
}
@Override
- TypeLatticeElement asNullable() {
+ public TypeLatticeElement asNullable() {
return isNullable() ? this : new ClassTypeLatticeElement(type, true, interfaces);
}
@@ -47,9 +46,4 @@
return this;
}
- @Override
- public TypeLatticeElement arrayGet(AppInfo appInfo) {
- return objectType(appInfo, true);
- }
-
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeLatticeElement.java
index a5f0b18..7273f19 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeLatticeElement.java
@@ -6,7 +6,7 @@
public class DoubleTypeLatticeElement extends WideTypeLatticeElement {
private static final DoubleTypeLatticeElement INSTANCE = new DoubleTypeLatticeElement();
- public static DoubleTypeLatticeElement getInstance() {
+ static DoubleTypeLatticeElement getInstance() {
return INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeLatticeElement.java
index d0e5f48..511d6b9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeLatticeElement.java
@@ -6,7 +6,7 @@
public class FloatTypeLatticeElement extends SingleTypeLatticeElement {
private static final FloatTypeLatticeElement INSTANCE = new FloatTypeLatticeElement();
- public static FloatTypeLatticeElement getInstance() {
+ static FloatTypeLatticeElement getInstance() {
return INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeLatticeElement.java
index 8b71446..02594a4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeLatticeElement.java
@@ -6,7 +6,7 @@
public class IntTypeLatticeElement extends SingleTypeLatticeElement {
private static final IntTypeLatticeElement INSTANCE = new IntTypeLatticeElement();
- public static IntTypeLatticeElement getInstance() {
+ static IntTypeLatticeElement getInstance() {
return INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeLatticeElement.java
index 92b3e3d..e60eaa1 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeLatticeElement.java
@@ -6,7 +6,7 @@
public class LongTypeLatticeElement extends WideTypeLatticeElement {
private static final LongTypeLatticeElement INSTANCE = new LongTypeLatticeElement();
- public static LongTypeLatticeElement getInstance() {
+ static LongTypeLatticeElement getInstance() {
return INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/NullLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/NullLatticeElement.java
new file mode 100644
index 0000000..caad0a2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/NullLatticeElement.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.analysis.type;
+
+/**
+ * Encodes the following lattice.
+ *
+ * <pre>
+ * MAYBE NULL
+ * / \
+ * DEFINITELY DEFINITELY
+ * NULL NOT NULL
+ * \ /
+ * BOTTOM
+ * </pre>
+ */
+public class NullLatticeElement {
+
+ private static final NullLatticeElement BOTTOM = new NullLatticeElement();
+ private static final NullLatticeElement DEFINITELY_NULL = new NullLatticeElement();
+ private static final NullLatticeElement DEFINITELY_NOT_NULL = new NullLatticeElement();
+ private static final NullLatticeElement MAYBE_NULL = new NullLatticeElement();
+
+ private NullLatticeElement() {}
+
+ public boolean isDefinitelyNull() {
+ return this == DEFINITELY_NULL;
+ }
+
+ public boolean isDefinitelyNotNull() {
+ return this == DEFINITELY_NOT_NULL;
+ }
+
+ public NullLatticeElement leastUpperBound(NullLatticeElement other) {
+ if (this == BOTTOM) {
+ return other;
+ }
+ if (this == other || other == BOTTOM) {
+ return this;
+ }
+ return MAYBE_NULL;
+ }
+
+ public boolean lessThanOrEqual(NullLatticeElement other) {
+ return leastUpperBound(other) == other;
+ }
+
+ static NullLatticeElement bottom() {
+ return BOTTOM;
+ }
+
+ static NullLatticeElement definitelyNull() {
+ return DEFINITELY_NULL;
+ }
+
+ static NullLatticeElement definitelyNotNull() {
+ return DEFINITELY_NOT_NULL;
+ }
+
+ static NullLatticeElement maybeNull() {
+ return MAYBE_NULL;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeLatticeElement.java
index 2eb732d..53c67e4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeLatticeElement.java
@@ -18,8 +18,8 @@
}
@Override
- TypeLatticeElement asNullable() {
- return TopTypeLatticeElement.getInstance();
+ public TypeLatticeElement asNullable() {
+ return TypeLatticeElement.TOP;
}
@Override
@@ -44,13 +44,13 @@
case 'S':
case 'C':
case 'I':
- return IntTypeLatticeElement.getInstance();
+ return TypeLatticeElement.INT;
case 'F':
- return FloatTypeLatticeElement.getInstance();
+ return TypeLatticeElement.FLOAT;
case 'J':
- return LongTypeLatticeElement.getInstance();
+ return TypeLatticeElement.LONG;
case 'D':
- return DoubleTypeLatticeElement.getInstance();
+ return TypeLatticeElement.DOUBLE;
case 'V':
throw new InternalCompilerError("No value type for void type.");
default:
@@ -64,13 +64,13 @@
case CHAR:
case SHORT:
case INT:
- return IntTypeLatticeElement.getInstance();
+ return TypeLatticeElement.INT;
case FLOAT:
- return FloatTypeLatticeElement.getInstance();
+ return TypeLatticeElement.FLOAT;
case LONG:
- return LongTypeLatticeElement.getInstance();
+ return TypeLatticeElement.LONG;
case DOUBLE:
- return DoubleTypeLatticeElement.getInstance();
+ return TypeLatticeElement.DOUBLE;
default:
throw new Unreachable("Invalid numeric type '" + numericType + "'");
}
@@ -83,21 +83,21 @@
}
if (t1.isSingle()) {
if (t2.isSingle()) {
- return SingleTypeLatticeElement.getInstance();
+ return TypeLatticeElement.SINGLE;
}
assert t2.isWide();
- return TopTypeLatticeElement.getInstance();
+ return TypeLatticeElement.TOP;
}
assert t1.isWide();
if (t2.isWide()) {
- return WideTypeLatticeElement.getInstance();
+ return TypeLatticeElement.WIDE;
}
assert t2.isSingle();
- return TopTypeLatticeElement.getInstance();
+ return TypeLatticeElement.TOP;
}
public static TypeLatticeElement meet(TypeLatticeElement t1, TypeLatticeElement t2) {
- // TODO(b/72693244): !t1.isReference() && !t2.isReference();
+ assert !t1.isReference() && !t2.isReference();
// TODO(b/72693244): propagate constraints backward, e.g.,
// vz <- add vx(1, INT) vy(0, INT_OR_FLOAT_OR_NULL)
if (t1 == t2) {
@@ -125,7 +125,7 @@
return t2;
}
}
- return BottomTypeLatticeElement.getInstance();
+ return TypeLatticeElement.BOTTOM;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java
index f700b15..ef36c4e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeLatticeElement.java
@@ -12,8 +12,10 @@
import java.util.stream.Collectors;
public class ReferenceTypeLatticeElement extends TypeLatticeElement {
- private static final ReferenceTypeLatticeElement NULL =
+ private static final ReferenceTypeLatticeElement NULL_INSTANCE =
new ReferenceTypeLatticeElement(DexItemFactory.nullValueType, true);
+ private static final ReferenceTypeLatticeElement REFERENCE_INSTANCE =
+ new ReferenceTypeLatticeElement(DexItemFactory.unknownType, true);
final DexType type;
final Set<DexType> interfaces;
@@ -28,8 +30,12 @@
this.interfaces = Collections.unmodifiableSet(interfaces);
}
- public static ReferenceTypeLatticeElement getNullTypeLatticeElement() {
- return NULL;
+ static ReferenceTypeLatticeElement getNullTypeLatticeElement() {
+ return NULL_INSTANCE;
+ }
+
+ static ReferenceTypeLatticeElement getReferenceTypeLatticeElement() {
+ return REFERENCE_INSTANCE;
}
@Override
@@ -38,8 +44,13 @@
}
@Override
- TypeLatticeElement asNullable() {
- assert isNull();
+ public boolean isReferenceInstance() {
+ return type == DexItemFactory.unknownType;
+ }
+
+ @Override
+ public TypeLatticeElement asNullable() {
+ assert isNull() || isReferenceInstance();
return this;
}
@@ -50,8 +61,7 @@
@Override
public TypeLatticeElement arrayGet(AppInfo appInfo) {
- assert isNull();
- return this;
+ return isNull() ? this : BOTTOM;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/SingleTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/SingleTypeLatticeElement.java
index 0128b5e..2f719df 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/SingleTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/SingleTypeLatticeElement.java
@@ -13,7 +13,7 @@
super();
}
- public static SingleTypeLatticeElement getInstance() {
+ static SingleTypeLatticeElement getInstance() {
return SINGLE_INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java
index eeb22d3..7aba6dc 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java
@@ -14,11 +14,11 @@
}
@Override
- TypeLatticeElement asNullable() {
+ public TypeLatticeElement asNullable() {
return this;
}
- public static TopTypeLatticeElement getInstance() {
+ static TopTypeLatticeElement getInstance() {
return INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
index ffbd3fd..b8988c1 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
@@ -84,12 +84,12 @@
TypeLatticeElement derived;
if (argumentsSeen < 0) {
// Receiver
- derived = fromDexType(appInfo, encodedMethod.method.holder,
+ derived = fromDexType(encodedMethod.method.holder, appInfo,
// Now we try inlining even when the receiver could be null.
encodedMethod != context);
} else {
DexType argType = encodedMethod.method.proto.parameters.values[argumentsSeen];
- derived = fromDexType(appInfo, argType, true);
+ derived = fromDexType(argType, appInfo, true);
}
argumentsSeen++;
updateTypeOfValue(outValue, derived);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
index f0ae028..a09039c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.Value;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayDeque;
@@ -22,7 +23,21 @@
/**
* The base abstraction of lattice elements for local type analysis.
*/
-abstract public class TypeLatticeElement {
+public abstract class TypeLatticeElement {
+ public static final BottomTypeLatticeElement BOTTOM = BottomTypeLatticeElement.getInstance();
+ public static final TopTypeLatticeElement TOP = TopTypeLatticeElement.getInstance();
+ public static final IntTypeLatticeElement INT = IntTypeLatticeElement.getInstance();
+ public static final FloatTypeLatticeElement FLOAT = FloatTypeLatticeElement.getInstance();
+ public static final SingleTypeLatticeElement SINGLE = SingleTypeLatticeElement.getInstance();
+ public static final LongTypeLatticeElement LONG = LongTypeLatticeElement.getInstance();
+ public static final DoubleTypeLatticeElement DOUBLE = DoubleTypeLatticeElement.getInstance();
+ public static final WideTypeLatticeElement WIDE = WideTypeLatticeElement.getInstance();
+ public static final ReferenceTypeLatticeElement NULL =
+ ReferenceTypeLatticeElement.getNullTypeLatticeElement();
+ public static final ReferenceTypeLatticeElement REFERENCE =
+ ReferenceTypeLatticeElement.getReferenceTypeLatticeElement();
+
+ // TODO(b/72693244): Switch to NullLatticeElement.
private final boolean isNullable;
TypeLatticeElement(boolean isNullable) {
@@ -33,8 +48,14 @@
return isNullable;
}
- public boolean isNull() {
- return false;
+ public NullLatticeElement nullElement() {
+ if (isNull()) {
+ return NullLatticeElement.definitelyNull();
+ }
+ if (!isNullable()) {
+ return NullLatticeElement.definitelyNotNull();
+ }
+ return NullLatticeElement.maybeNull();
}
/**
@@ -42,7 +63,7 @@
*
* @return {@link TypeLatticeElement} a result of joining with null.
*/
- abstract TypeLatticeElement asNullable();
+ public abstract TypeLatticeElement asNullable();
/**
* Defines how to switch to non-nullable lattice element.
@@ -50,7 +71,7 @@
* @return {@link TypeLatticeElement} a similar lattice element with nullable flag flipped.
*/
public TypeLatticeElement asNonNullable() {
- return BottomTypeLatticeElement.getInstance();
+ return BOTTOM;
}
String isNullableString() {
@@ -74,7 +95,7 @@
return l1;
}
if (l1.isTop() || l2.isTop()) {
- return TopTypeLatticeElement.getInstance();
+ return TOP;
}
if (l1.isNull()) {
return l2.asNullable();
@@ -86,16 +107,25 @@
return l2.isPrimitive()
? PrimitiveTypeLatticeElement.join(
l1.asPrimitiveTypeLatticeElement(), l2.asPrimitiveTypeLatticeElement())
- : TopTypeLatticeElement.getInstance();
+ : TOP;
}
if (l2.isPrimitive()) {
// By the above case, !(l1.isPrimitive())
- return TopTypeLatticeElement.getInstance();
+ return TOP;
}
- // From now on, l1 and l2 are reference types, i.e., either ArrayType or ClassType.
+ // From now on, l1 and l2 are reference types, but might be imprecise yet.
+ assert l1.isReference() && l2.isReference();
+ if (!l1.isPreciseType() || !l2.isPreciseType()) {
+ if (l1.isReferenceInstance()) {
+ return l1;
+ }
+ assert l2.isReferenceInstance();
+ return l2;
+ }
+ // From now on, l1 and l2 are precise reference types, i.e., either ArrayType or ClassType.
boolean isNullable = l1.isNullable() || l2.isNullable();
if (l1.getClass() != l2.getClass()) {
- return objectType(appInfo, isNullable);
+ return objectClassType(appInfo, isNullable);
}
// From now on, l1.getClass() == l2.getClass()
if (l1.isArrayType()) {
@@ -122,7 +152,7 @@
assert a1BaseReferenceType.isClassType() && a2BaseReferenceType.isClassType();
// If any nestings hit zero object is the join.
if (a1Nesting == 0 || a2Nesting == 0) {
- return objectType(appInfo, isNullable);
+ return objectClassType(appInfo, isNullable);
}
// If the nestings differ the join is the smallest nesting level.
if (a1Nesting != a2Nesting) {
@@ -238,7 +268,7 @@
public static TypeLatticeElement join(
AppInfo appInfo, Stream<DexType> types, boolean isNullable) {
- return join(appInfo, types.map(t -> fromDexType(appInfo, t, isNullable)));
+ return join(appInfo, types.map(t -> fromDexType(t, appInfo, isNullable)));
}
/**
@@ -350,7 +380,20 @@
|| isDouble();
}
- static ClassTypeLatticeElement objectType(AppInfo appInfo, boolean isNullable) {
+ public boolean isNull() {
+ return false;
+ }
+
+ public boolean isReferenceInstance() {
+ return false;
+ }
+
+ public int requiredRegisters() {
+ assert !isBottom() && !isTop();
+ return isWide() ? 2 : 1;
+ }
+
+ public static ClassTypeLatticeElement objectClassType(AppInfo appInfo, boolean isNullable) {
return new ClassTypeLatticeElement(appInfo.dexItemFactory.objectType, isNullable);
}
@@ -360,9 +403,17 @@
isNullable);
}
- public static TypeLatticeElement fromDexType(AppInfo appInfo, DexType type, boolean isNullable) {
+ public static TypeLatticeElement classClassType(AppInfo appInfo) {
+ return fromDexType(appInfo.dexItemFactory.classType, appInfo, false);
+ }
+
+ public static TypeLatticeElement stringClassType(AppInfo appInfo) {
+ return fromDexType(appInfo.dexItemFactory.stringType, appInfo, false);
+ }
+
+ public static TypeLatticeElement fromDexType(DexType type, AppInfo appInfo, boolean isNullable) {
if (type == DexItemFactory.nullValueType) {
- return ReferenceTypeLatticeElement.getNullTypeLatticeElement();
+ return NULL;
}
if (type.isPrimitiveType()) {
return PrimitiveTypeLatticeElement.fromDexType(type);
@@ -379,16 +430,60 @@
return new ArrayTypeLatticeElement(type, isNullable);
}
+ public static TypeLatticeElement fromDexType(DexType type) {
+ if (type == DexItemFactory.nullValueType) {
+ return NULL;
+ }
+ return fromTypeDescriptorChar((char) type.descriptor.content[0]);
+ }
+
+ public static TypeLatticeElement fromTypeDescriptorChar(char descriptor) {
+ switch (descriptor) {
+ case 'L':
+ // TODO(jsjeon): class type with Object?
+ case '[':
+ // TODO(jsjeon): array type with Object?
+ return REFERENCE;
+ default:
+ return PrimitiveTypeLatticeElement.fromTypeDescriptorChar(descriptor);
+ }
+ }
+
+ public static TypeLatticeElement fromMemberType(MemberType type) {
+ switch (type) {
+ case BOOLEAN:
+ case BYTE:
+ case CHAR:
+ case SHORT:
+ case INT:
+ return INT;
+ case FLOAT:
+ return FLOAT;
+ case INT_OR_FLOAT:
+ return SINGLE;
+ case LONG:
+ return LONG;
+ case DOUBLE:
+ return DOUBLE;
+ case LONG_OR_DOUBLE:
+ return WIDE;
+ case OBJECT:
+ return REFERENCE;
+ default:
+ throw new Unreachable("Unexpected member type: " + type);
+ }
+ }
+
public static TypeLatticeElement newArray(DexType arrayType, boolean isNullable) {
return new ArrayTypeLatticeElement(arrayType, isNullable);
}
public TypeLatticeElement arrayGet(AppInfo appInfo) {
- return BottomTypeLatticeElement.getInstance();
+ return BOTTOM;
}
public TypeLatticeElement checkCast(AppInfo appInfo, DexType castType) {
- TypeLatticeElement castTypeLattice = fromDexType(appInfo, castType, isNullable());
+ TypeLatticeElement castTypeLattice = fromDexType(castType, appInfo, isNullable());
if (lessThanOrEqual(appInfo, this, castTypeLattice)) {
return this;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/WideTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/WideTypeLatticeElement.java
index ec0b846..53c0da1 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/WideTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/WideTypeLatticeElement.java
@@ -13,7 +13,7 @@
super();
}
- public static WideTypeLatticeElement getInstance() {
+ static WideTypeLatticeElement getInstance() {
return WIDE_INSTANCE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
index 296fba5..cc154e9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.ir.analysis.constant.Bottom;
import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import java.util.function.Function;
@@ -139,20 +140,20 @@
ConstNumber newConst;
if (type == NumericType.INT) {
int result = foldIntegers(leftConst.getIntValue(), rightConst.getIntValue());
- Value value = code.createValue(ValueType.INT, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.INT, getLocalInfo());
newConst = new ConstNumber(value, result);
} else if (type == NumericType.LONG) {
long result = foldLongs(leftConst.getLongValue(), rightConst.getLongValue());
- Value value = code.createValue(ValueType.LONG, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.LONG, getLocalInfo());
newConst = new ConstNumber(value, result);
} else if (type == NumericType.FLOAT) {
float result = foldFloat(leftConst.getFloatValue(), rightConst.getFloatValue());
- Value value = code.createValue(ValueType.FLOAT, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.FLOAT, getLocalInfo());
newConst = new ConstNumber(value, Float.floatToIntBits(result));
} else {
assert type == NumericType.DOUBLE;
double result = foldDouble(leftConst.getDoubleValue(), rightConst.getDoubleValue());
- Value value = code.createValue(ValueType.DOUBLE, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.DOUBLE, getLocalInfo());
newConst = new ConstNumber(value, Double.doubleToLongBits(result));
}
return new ConstLatticeElement(newConst);
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index 0c8f214..e222eaa 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.IntTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -107,7 +106,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return IntTypeLatticeElement.getInstance();
+ return TypeLatticeElement.INT;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 8a2c169..a8c9b2f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -6,11 +6,13 @@
import static com.android.tools.r8.ir.code.IRCode.INSTRUCTION_NUMBER_DELTA;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DebugLocalInfo.PrintLevel;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Phi.RegisterReadType;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.conversion.IRBuilder;
@@ -68,6 +70,11 @@
return true;
}
+ public boolean verifyTypes(AppInfo appInfo) {
+ assert instructions.stream().allMatch(instruction -> instruction.verifyTypes(appInfo));
+ return true;
+ }
+
public void setLocalsAtEntry(Int2ReferenceMap<DebugLocalInfo> localsAtEntry) {
this.localsAtEntry = localsAtEntry;
}
@@ -1174,10 +1181,11 @@
return block;
}
- public static BasicBlock createRethrowBlock(IRCode code, Position position) {
+ public static BasicBlock createRethrowBlock(
+ IRCode code, Position position, TypeLatticeElement guardTypeLattice) {
BasicBlock block = new BasicBlock();
- MoveException moveException =
- new MoveException(new Value(code.valueNumberGenerator.next(), ValueType.OBJECT, null));
+ MoveException moveException = new MoveException(
+ new Value(code.valueNumberGenerator.next(), guardTypeLattice, null));
moveException.setPosition(position);
Throw throwInstruction = new Throw(moveException.outValue);
throwInstruction.setPosition(position);
@@ -1438,11 +1446,13 @@
Consumer<BasicBlock> onNewBlock) {
List<BasicBlock> predecessors = this.getPredecessors();
boolean hasMoveException = entry().isMoveException();
+ TypeLatticeElement exceptionTypeLattice = null;
MoveException move = null;
Position position = entry().getPosition();
if (hasMoveException) {
// Remove the move-exception instruction.
move = entry().asMoveException();
+ exceptionTypeLattice = move.outValue().getTypeLattice();
assert move.getDebugValues().isEmpty();
getInstructions().remove(0);
}
@@ -1458,7 +1468,10 @@
newBlock.setNumber(nextBlockNumber++);
newPredecessors.add(newBlock);
if (hasMoveException) {
- Value value = new Value(valueNumberGenerator.next(), ValueType.OBJECT, move.getLocalInfo());
+ Value value = new Value(
+ valueNumberGenerator.next(),
+ exceptionTypeLattice,
+ move.getLocalInfo());
values.add(value);
MoveException newMove = new MoveException(value);
newBlock.add(newMove);
@@ -1483,7 +1496,7 @@
new Phi(
valueNumberGenerator.next(),
this,
- ValueType.OBJECT,
+ exceptionTypeLattice,
move.getLocalInfo(),
RegisterReadType.NORMAL);
phi.addOperands(values);
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 fbbe2fd..7caaff9 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
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Phi.RegisterReadType;
import com.android.tools.r8.utils.IteratorUtils;
import com.google.common.collect.ImmutableList;
@@ -363,8 +364,11 @@
int i = 0;
if (downcast != null) {
+ Value receiver = invoke.inValues().get(0);
+ TypeLatticeElement castTypeLattice = TypeLatticeElement.fromDexType(
+ downcast, appInfo, receiver.getTypeLattice().isNullable());
CheckCast castInstruction =
- new CheckCast(code.createValue(ValueType.OBJECT), invoke.inValues().get(0), downcast);
+ new CheckCast(code.createValue(castTypeLattice), receiver, downcast);
castInstruction.setPosition(invoke.getPosition());
// Splice in the check cast operation.
@@ -544,7 +548,7 @@
new Phi(
code.valueNumberGenerator.next(),
newExitBlock,
- returnType,
+ returnType.toTypeLattice(),
null,
RegisterReadType.NORMAL);
phi.addOperands(operands);
diff --git a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
index 4c1824b..8d461bd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
@@ -123,6 +123,47 @@
}
@Override
+ public boolean verifyTypes(AppInfo appInfo) {
+ TypeLatticeElement inType = object().getTypeLattice();
+
+ // TODO(b/72693244): There should never be a value with imprecise type lattice.
+ if (!inType.isPreciseType()) {
+ return true;
+ }
+
+ TypeLatticeElement outType = outValue().getTypeLattice();
+ TypeLatticeElement castType =
+ TypeLatticeElement.fromDexType(getType(), appInfo, inType.isNullable());
+
+ if (TypeLatticeElement.lessThanOrEqual(appInfo, inType, castType)) {
+ // Cast can be removed. Check that it is sound to replace all users of the out-value by the
+ // in-value.
+ assert TypeLatticeElement.lessThanOrEqual(appInfo, inType, outType);
+
+ // TODO(b/72693244): Consider checking equivalence. This requires that the types are always
+ // as precise as possible, though, meaning that almost all changes to the IR must be followed
+ // by a fix-point analysis.
+ // assert outType.equals(inType);
+ } else {
+ // We don't have enough information to remove the cast. Check that the out-value does not
+ // have a more precise type than the cast-type.
+ assert castType.asNullable().equals(outType.asNullable());
+
+ // Check soundness of null information.
+ assert inType.nullElement().lessThanOrEqual(outType.nullElement());
+
+ // Since we cannot remove the cast the in-value must be different from null.
+ assert !inType.isNull();
+
+ // TODO(b/72693244): Consider checking equivalence. This requires that the types are always
+ // as precise as possible, though, meaning that almost all changes to the IR must be followed
+ // by a fix-point analysis.
+ // assert outType.equals(castType);
+ }
+ return true;
+ }
+
+ @Override
public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {
helper.loadInValues(this, it);
helper.storeOutValue(this, it);
diff --git a/src/main/java/com/android/tools/r8/ir/code/Cmp.java b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
index 239e404..4c2529d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Cmp.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
@@ -11,9 +11,11 @@
import com.android.tools.r8.code.CmplFloat;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.ir.analysis.constant.Bottom;
import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.utils.LongInterval;
@@ -179,7 +181,7 @@
result = (int) Math.signum(left - right);
}
}
- Value value = code.createValue(ValueType.INT, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.INT, getLocalInfo());
ConstNumber newConst = new ConstNumber(value, result);
return new ConstLatticeElement(newConst);
} else if (leftLattice.isValueRange() && rightLattice.isConst()) {
@@ -207,7 +209,7 @@
return Bottom.getInstance();
}
int result = Integer.signum(Long.compare(leftRange.getMin(), rightRange.getMin()));
- Value value = code.createValue(ValueType.INT, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.INT, getLocalInfo());
ConstNumber newConst = new ConstNumber(value, result);
return new ConstLatticeElement(newConst);
}
@@ -226,4 +228,10 @@
public void buildCf(CfBuilder builder) {
builder.add(new CfCmp(bias, type));
}
+
+ @Override
+ public TypeLatticeElement evaluate(AppInfo appInfo) {
+ return TypeLatticeElement.INT;
+ }
+
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index 2da242e..401656c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -105,7 +105,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return TypeLatticeElement.fromDexType(appInfo, appInfo.dexItemFactory.classType, false);
+ return TypeLatticeElement.fromDexType(appInfo.dexItemFactory.classType, appInfo, false);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
index b319dbb..ffc4359 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
@@ -91,7 +91,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return TypeLatticeElement.fromDexType(appInfo, appInfo.dexItemFactory.methodHandleType, false);
+ return TypeLatticeElement.fromDexType(appInfo.dexItemFactory.methodHandleType, appInfo, false);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
index 4159c31..81d7b28 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
@@ -91,7 +91,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return TypeLatticeElement.fromDexType(appInfo, appInfo.dexItemFactory.methodTypeType, false);
+ return TypeLatticeElement.fromDexType(appInfo.dexItemFactory.methodTypeType, appInfo, false);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 73cf1c2..fa15046 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -21,15 +21,7 @@
import com.android.tools.r8.ir.analysis.constant.Bottom;
import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
import com.android.tools.r8.ir.analysis.constant.LatticeElement;
-import com.android.tools.r8.ir.analysis.type.BottomTypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.DoubleTypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.FloatTypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.IntTypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.LongTypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.ReferenceTypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.SingleTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.WideTypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.utils.NumberUtils;
@@ -49,8 +41,10 @@
}
public static ConstNumber copyOf(IRCode code, ConstNumber original) {
- Value newValue =
- new Value(code.valueNumberGenerator.next(), original.outType(), original.getLocalInfo());
+ Value newValue = new Value(
+ code.valueNumberGenerator.next(),
+ original.outValue().getTypeLattice(),
+ original.getLocalInfo());
return new ConstNumber(newValue, original.getRawValue());
}
@@ -278,22 +272,23 @@
// TODO(b/72693244): IR builder should know the type and assign a proper type lattice.
switch (outType()) {
case OBJECT:
- return ReferenceTypeLatticeElement.getNullTypeLatticeElement();
+ assert isZero();
+ return TypeLatticeElement.NULL;
case INT:
- return IntTypeLatticeElement.getInstance();
+ return TypeLatticeElement.INT;
case FLOAT:
- return FloatTypeLatticeElement.getInstance();
+ return TypeLatticeElement.FLOAT;
case LONG:
- return LongTypeLatticeElement.getInstance();
+ return TypeLatticeElement.LONG;
case DOUBLE:
- return DoubleTypeLatticeElement.getInstance();
+ return TypeLatticeElement.DOUBLE;
case INT_OR_FLOAT:
- return SingleTypeLatticeElement.getInstance();
+ return TypeLatticeElement.SINGLE;
case LONG_OR_DOUBLE:
- return WideTypeLatticeElement.getInstance();
+ return TypeLatticeElement.DOUBLE;
case INT_OR_FLOAT_OR_NULL:
default:
- return BottomTypeLatticeElement.getInstance();
+ return TypeLatticeElement.BOTTOM;
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index b5a3b90..85fd784 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -28,7 +28,9 @@
public static ConstString copyOf(IRCode code, ConstString original) {
Value newValue =
- new Value(code.valueNumberGenerator.next(), original.outType(), original.getLocalInfo());
+ new Value(code.valueNumberGenerator.next(),
+ original.outValue().getTypeLattice(),
+ original.getLocalInfo());
return new ConstString(newValue, original.getValue());
}
@@ -131,6 +133,6 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return TypeLatticeElement.fromDexType(appInfo, appInfo.dexItemFactory.stringType, false);
+ return TypeLatticeElement.fromDexType(appInfo.dexItemFactory.stringType, appInfo, false);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java b/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java
index 1427e12..0578506 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FixedRegisterValue.java
@@ -3,14 +3,16 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+
// Value that has a fixed register allocated. These are used for inserting spill, restore, and phi
// moves in the spilling register allocator.
public class FixedRegisterValue extends Value {
private final int register;
- public FixedRegisterValue(ValueType type, int register) {
+ public FixedRegisterValue(TypeLatticeElement typeLattice, int register) {
// Set local info to null since these values are never representatives of live-ranges.
- super(-1, type, null);
+ super(-1, typeLattice, null);
setNeedsRegister(true);
this.register = register;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 1cafe2a..92e2ddb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableList;
@@ -22,6 +24,7 @@
import java.util.Map;
import java.util.Queue;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
public class IRCode {
@@ -407,6 +410,7 @@
assert consistentDefUseChains();
assert validThrowingInstructions();
assert noCriticalEdges();
+ assert noBottomTypeLatticeLeft();
return true;
}
@@ -420,6 +424,11 @@
return true;
}
+ public boolean verifyTypes(AppInfo appInfo) {
+ assert blocks.stream().allMatch(block -> block.verifyTypes(appInfo));
+ return true;
+ }
+
private boolean noCriticalEdges() {
for (BasicBlock block : blocks) {
List<BasicBlock> predecessors = block.getPredecessors();
@@ -605,6 +614,29 @@
return true;
}
+ private boolean noBottomTypeLatticeLeft() {
+ return verifySSATypeLattice(lattice -> !lattice.isBottom());
+ }
+
+ private boolean noImpreciseTypeLatticeLeft() {
+ return verifySSATypeLattice(TypeLatticeElement::isPreciseType);
+ }
+
+ private boolean verifySSATypeLattice(Predicate<TypeLatticeElement> tester) {
+ for (BasicBlock block : blocks) {
+ for (Instruction instruction : block.getInstructions()) {
+ Value outValue = instruction.outValue();
+ if (outValue != null) {
+ assert tester.test(outValue.getTypeLattice());
+ }
+ }
+ for (Phi phi : block.getPhis()) {
+ assert tester.test(phi.getTypeLattice());
+ }
+ }
+ return true;
+ }
+
public InstructionIterator instructionIterator() {
return new IRCodeInstructionsIterator(this);
}
@@ -683,16 +715,20 @@
return thisValue;
}
- public Value createValue(ValueType valueType, DebugLocalInfo local) {
- return new Value(valueNumberGenerator.next(), valueType, local);
+ public Value createValue(TypeLatticeElement typeLattice, DebugLocalInfo local) {
+ return new Value(valueNumberGenerator.next(), typeLattice, local);
}
- public Value createValue(ValueType valueType) {
- return createValue(valueType, null);
+ public Value createValue(TypeLatticeElement typeLattice) {
+ return createValue(typeLattice, null);
+ }
+
+ public Value createValue(DebugLocalInfo local) {
+ return createValue(TypeLatticeElement.BOTTOM, local);
}
public ConstNumber createIntConstant(int value) {
- Value out = createValue(ValueType.INT);
+ Value out = createValue(TypeLatticeElement.INT);
return new ConstNumber(out, value);
}
@@ -701,7 +737,7 @@
}
public ConstNumber createConstNull() {
- Value out = createValue(ValueType.OBJECT);
+ Value out = createValue(TypeLatticeElement.NULL);
return new ConstNumber(out, 0);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/If.java b/src/main/java/com/android/tools/r8/ir/code/If.java
index 266069b..4fdb047 100644
--- a/src/main/java/com/android/tools/r8/ir/code/If.java
+++ b/src/main/java/com/android/tools/r8/ir/code/If.java
@@ -228,12 +228,13 @@
@Override
public void buildCf(CfBuilder builder) {
+ ValueType ifType = inValues.get(0).type;
if (inValues.size() == 1) {
- builder.add(new CfIf(type, inValues.get(0).type, builder.getLabel(getTrueTarget())));
+ builder.add(new CfIf(type, ifType, builder.getLabel(getTrueTarget())));
return;
}
assert inValues.size() == 2;
assert inValues.get(0).type == inValues.get(1).type;
- builder.add(new CfIfCmp(type, inValues.get(0).type, builder.getLabel(getTrueTarget())));
+ builder.add(new CfIfCmp(type, ifType, builder.getLabel(getTrueTarget())));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index 0a919bb..0c8c372 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -135,7 +135,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return TypeLatticeElement.fromDexType(appInfo, field.type, true);
+ return TypeLatticeElement.fromDexType(field.type, appInfo, true);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
index c5dc5e4..8e2446b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.IntTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -87,7 +86,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return IntTypeLatticeElement.getInstance();
+ return TypeLatticeElement.INT;
}
@Override
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 8f1a004..d3355b4 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
@@ -1089,6 +1089,11 @@
"Implement type lattice evaluation for: " + getInstructionName());
}
+ public boolean verifyTypes(AppInfo appInfo) {
+ // TODO(b/72693244): for instructions with invariant out type, we can verify type directly here.
+ return true;
+ }
+
/**
* Indicates whether the instruction throws a NullPointerException if the object denoted by the
* given value is null at runtime execution.
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index 6e7c207..b755336 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -280,6 +280,6 @@
if (returnType.isVoidType()) {
throw new Unreachable("void methods have no type.");
}
- return TypeLatticeElement.fromDexType(appInfo, returnType, true);
+ return TypeLatticeElement.fromDexType(returnType, appInfo, true);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
index 4b34ca1..ad3d344 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.ir.analysis.constant.Bottom;
import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import java.util.function.Function;
@@ -116,7 +117,7 @@
ConstNumber newConst;
if (type == NumericType.INT) {
int result = foldIntegers(leftConst.getIntValue(), rightConst.getIntValue());
- Value value = code.createValue(ValueType.INT, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.INT, getLocalInfo());
newConst = new ConstNumber(value, result);
} else {
assert type == NumericType.LONG;
@@ -128,7 +129,7 @@
right = rightConst.getLongValue();
}
long result = foldLongs(leftConst.getLongValue(), right);
- Value value = code.createValue(ValueType.LONG, getLocalInfo());
+ Value value = code.createValue(TypeLatticeElement.LONG, getLocalInfo());
newConst = new ConstNumber(value, result);
}
return new ConstLatticeElement(newConst);
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index c92ac50..562b33d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -94,14 +94,15 @@
return true;
}
- private Set<DexType> collectExceptionTypes(DexItemFactory dexItemFactory) {
- Set<DexType> exceptionTypes = new HashSet<>(getBlock().getPredecessors().size());
- for (BasicBlock block : getBlock().getPredecessors()) {
+ public static Set<DexType> collectExceptionTypes(
+ BasicBlock currentBlock, DexItemFactory dexItemFactory) {
+ Set<DexType> exceptionTypes = new HashSet<>(currentBlock.getPredecessors().size());
+ for (BasicBlock block : currentBlock.getPredecessors()) {
int size = block.getCatchHandlers().size();
List<BasicBlock> targets = block.getCatchHandlers().getAllTargets();
List<DexType> guards = block.getCatchHandlers().getGuards();
for (int i = 0; i < size; i++) {
- if (targets.get(i) == getBlock()) {
+ if (targets.get(i) == currentBlock) {
DexType guard = guards.get(i);
exceptionTypes.add(
guard == dexItemFactory.catchAllType
@@ -115,14 +116,14 @@
@Override
public DexType computeVerificationType(TypeVerificationHelper helper) {
- return helper.join(collectExceptionTypes(helper.getFactory()));
+ return helper.join(collectExceptionTypes(getBlock(), helper.getFactory()));
}
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- Set<DexType> exceptionTypes = collectExceptionTypes(appInfo.dexItemFactory);
+ Set<DexType> exceptionTypes = collectExceptionTypes(getBlock(), appInfo.dexItemFactory);
return TypeLatticeElement.join(
appInfo,
- exceptionTypes.stream().map(t -> TypeLatticeElement.fromDexType(appInfo, t, false)));
+ exceptionTypes.stream().map(t -> TypeLatticeElement.fromDexType(t, appInfo, false)));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Neg.java b/src/main/java/com/android/tools/r8/ir/code/Neg.java
index 16b2922..86e7440 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Neg.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Neg.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.ir.analysis.constant.Bottom;
import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import java.util.function.Function;
@@ -81,8 +83,8 @@
LatticeElement sourceLattice = getLatticeElement.apply(source());
if (sourceLattice.isConst()) {
ConstNumber sourceConst = sourceLattice.asConst().getConstNumber();
- ValueType valueType = ValueType.fromNumericType(type);
- Value value = code.createValue(valueType, getLocalInfo());
+ TypeLatticeElement typeLattice = PrimitiveTypeLatticeElement.fromNumericType(type);
+ Value value = code.createValue(typeLattice, getLocalInfo());
ConstNumber newConst;
if (type == NumericType.INT) {
newConst = new ConstNumber(value, -sourceConst.getIntValue());
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 8dbc38b..29b263f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -107,7 +107,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return TypeLatticeElement.fromDexType(appInfo, clazz, false);
+ return TypeLatticeElement.fromDexType(clazz, appInfo, false);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Not.java b/src/main/java/com/android/tools/r8/ir/code/Not.java
index 1037c34..55918cc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Not.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Not.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.ir.analysis.constant.Bottom;
import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import java.util.function.Function;
@@ -35,8 +37,8 @@
LatticeElement sourceLattice = getLatticeElement.apply(source());
if (sourceLattice.isConst()) {
ConstNumber sourceConst = sourceLattice.asConst().getConstNumber();
- ValueType valueType = ValueType.fromNumericType(type);
- Value value = code.createValue(valueType, getLocalInfo());
+ TypeLatticeElement typeLattice = PrimitiveTypeLatticeElement.fromNumericType(type);
+ Value value = code.createValue(typeLattice, getLocalInfo());
ConstNumber newConst;
if (type == NumericType.INT) {
newConst = new ConstNumber(value, ~sourceConst.getIntValue());
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 f3301e7..c688e6d 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
@@ -8,6 +8,7 @@
import com.android.tools.r8.errors.InvalidDebugInfoException;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.BasicBlock.EdgeType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.utils.CfgPrinter;
@@ -41,10 +42,10 @@
public Phi(
int number,
BasicBlock block,
- ValueType type,
+ TypeLatticeElement typeLattice,
DebugLocalInfo local,
RegisterReadType readType) {
- super(number, type, local);
+ super(number, typeLattice, local);
this.block = block;
this.readType = readType;
block.addPhi(this);
@@ -95,7 +96,7 @@
assert readType == RegisterReadType.DEBUG;
BasicBlock block = getBlock();
InstructionListIterator it = block.listIterator();
- Value value = new Value(builder.getValueNumberGenerator().next(), type, null);
+ Value value = new Value(builder.getValueNumberGenerator().next(), getTypeLattice(), null);
Position position = block.getPosition();
Instruction definition = new DebugLocalUninitialized(value);
definition.setBlock(block);
diff --git a/src/main/java/com/android/tools/r8/ir/code/StackValue.java b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
index 46aa5db..d9dabef 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StackValue.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
@@ -5,14 +5,15 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
public class StackValue extends Value {
private final int height;
private final DexType objectType;
- private StackValue(DexType objectType, ValueType valueType, int height) {
- super(Value.UNDEFINED_NUMBER, valueType, null);
+ private StackValue(DexType objectType, TypeLatticeElement typeLattice, int height) {
+ super(Value.UNDEFINED_NUMBER, typeLattice, null);
this.height = height;
this.objectType = objectType;
assert height >= 0;
@@ -20,12 +21,12 @@
public static StackValue forObjectType(DexType type, int height) {
assert DexItemFactory.nullValueType == type || type.isClassType() || type.isArrayType();
- return new StackValue(type, ValueType.OBJECT, height);
+ return new StackValue(type, TypeLatticeElement.fromDexType(type), height);
}
public static StackValue forNonObjectType(ValueType valueType, int height) {
assert valueType.isPreciseType() && !valueType.isObject();
- return new StackValue(null, valueType, height);
+ return new StackValue(null, valueType.toTypeLattice(), height);
}
public int getHeight() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index 50591b0..9ef7ed4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -145,7 +145,7 @@
@Override
public TypeLatticeElement evaluate(AppInfo appInfo) {
- return TypeLatticeElement.fromDexType(appInfo, field.type, true);
+ return TypeLatticeElement.fromDexType(field.type, appInfo, true);
}
@Override
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 48b8f5b..26c2e60 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
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.ir.analysis.type.BottomTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
import com.android.tools.r8.origin.Origin;
@@ -43,6 +42,7 @@
new MethodPosition(method)));
}
type = meet;
+ typeLattice = meet.toTypeLattice();
}
public void markNonDebugLocalRead() {
@@ -113,7 +113,8 @@
public static final int UNDEFINED_NUMBER = -1;
- public static final Value UNDEFINED = new Value(UNDEFINED_NUMBER, ValueType.OBJECT, null);
+ public static final Value UNDEFINED =
+ new Value(UNDEFINED_NUMBER, TypeLatticeElement.BOTTOM, null);
protected final int number;
// TODO(b/72693244): deprecate once typeLattice is landed.
@@ -134,12 +135,13 @@
private boolean knownToBeBoolean = false;
private LongInterval valueRange;
private DebugData debugData;
- private TypeLatticeElement typeLattice = BottomTypeLatticeElement.getInstance();
+ private TypeLatticeElement typeLattice;
- public Value(int number, ValueType type, DebugLocalInfo local) {
+ public Value(int number, TypeLatticeElement typeLattice, DebugLocalInfo local) {
this.number = number;
- this.type = type;
+ this.type = ValueType.fromTypeLattice(typeLattice);
this.debugData = local == null ? null : new DebugData(local);
+ this.typeLattice = typeLattice;
}
public boolean isFixedRegisterValue() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueType.java b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
index 99f949d..2d53749 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
public enum ValueType {
OBJECT,
@@ -181,4 +182,54 @@
throw new Unreachable("Invalid numeric type '" + type + "'");
}
}
+
+ public static ValueType fromTypeLattice(TypeLatticeElement typeLatticeElement) {
+ if (typeLatticeElement.isBottom()) {
+ return INT_OR_FLOAT_OR_NULL;
+ }
+ if (typeLatticeElement.isReference()) {
+ return OBJECT;
+ }
+ if (typeLatticeElement.isInt()) {
+ return INT;
+ }
+ if (typeLatticeElement.isFloat()) {
+ return FLOAT;
+ }
+ if (typeLatticeElement.isLong()) {
+ return LONG;
+ }
+ if (typeLatticeElement.isDouble()) {
+ return DOUBLE;
+ }
+ if (typeLatticeElement.isSingle()) {
+ return INT_OR_FLOAT;
+ }
+ if (typeLatticeElement.isWide()) {
+ return LONG_OR_DOUBLE;
+ }
+ throw new Unreachable("Invalid type lattice '" + typeLatticeElement + "'");
+ }
+
+ public TypeLatticeElement toTypeLattice() {
+ switch (this) {
+ case OBJECT:
+ return TypeLatticeElement.REFERENCE;
+ case INT:
+ return TypeLatticeElement.INT;
+ case FLOAT:
+ return TypeLatticeElement.FLOAT;
+ case INT_OR_FLOAT:
+ return TypeLatticeElement.SINGLE;
+ case LONG:
+ return TypeLatticeElement.LONG;
+ case DOUBLE:
+ return TypeLatticeElement.DOUBLE;
+ case LONG_OR_DOUBLE:
+ return TypeLatticeElement.WIDE;
+ case INT_OR_FLOAT_OR_NULL:
+ default:
+ return TypeLatticeElement.BOTTOM;
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 6fbafcb..9e14033 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -22,10 +22,10 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.CanonicalPositions;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfState.Snapshot;
import com.android.tools.r8.ir.conversion.IRBuilder.BlockInfo;
import com.android.tools.r8.origin.Origin;
@@ -347,9 +347,9 @@
if (type.isBooleanType()) {
builder.addBooleanNonThisArgument(argumentRegister++);
} else {
- ValueType valueType = ValueType.fromDexType(type);
- builder.addNonThisArgument(argumentRegister, valueType);
- argumentRegister += valueType.requiredRegisters();
+ TypeLatticeElement typeLattice = TypeLatticeElement.fromDexType(type);
+ builder.addNonThisArgument(argumentRegister, typeLattice);
+ argumentRegister += typeLattice.requiredRegisters();
}
}
}
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 b588408..b7c99b1 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
@@ -40,10 +40,10 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.CanonicalPositions;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.ValueType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -71,7 +71,7 @@
private Position currentPosition = null;
private final CanonicalPositions canonicalPositions;
- private final List<ValueType> argumentTypes;
+ private final List<TypeLatticeElement> argumentTypes;
private List<DexDebugEntry> debugEntries = null;
// In case of inlining the position of the invoke in the caller.
@@ -150,9 +150,9 @@
builder.addThisArgument(register);
++register;
}
- for (ValueType type : argumentTypes) {
- builder.addNonThisArgument(register, type);
- register += type.requiredRegisters();
+ for (TypeLatticeElement typeLattice : argumentTypes) {
+ builder.addNonThisArgument(register, typeLattice);
+ register += typeLattice.requiredRegisters();
}
}
@@ -303,12 +303,12 @@
arrayFilledDataPayloadResolver.getData(payloadOffset));
}
- private List<ValueType> computeArgumentTypes() {
- List<ValueType> types = new ArrayList<>(proto.parameters.size());
+ private List<TypeLatticeElement> computeArgumentTypes() {
+ List<TypeLatticeElement> types = new ArrayList<>(proto.parameters.size());
String shorty = proto.shorty.toString();
for (int i = 1; i < proto.shorty.size; i++) {
- ValueType valueType = ValueType.fromTypeDescriptorChar(shorty.charAt(i));
- types.add(valueType);
+ TypeLatticeElement typeLattice = TypeLatticeElement.fromTypeDescriptorChar(shorty.charAt(i));
+ types.add(typeLattice);
}
return types;
}
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 deac5eb..b471e12 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
@@ -20,6 +20,8 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Add;
import com.android.tools.r8.ir.code.And;
import com.android.tools.r8.ir.code.Argument;
@@ -118,6 +120,11 @@
* http://compilers.cs.uni-saarland.de/papers/bbhlmz13cc.pdf
*/
public class IRBuilder {
+ private static final TypeLatticeElement INT = TypeLatticeElement.INT;
+ private static final TypeLatticeElement FLOAT = TypeLatticeElement.FLOAT;
+ private static final TypeLatticeElement LONG = TypeLatticeElement.LONG;
+ private static final TypeLatticeElement DOUBLE = TypeLatticeElement.DOUBLE;
+ private static final TypeLatticeElement NULL = TypeLatticeElement.NULL;
public static final int INITIAL_BLOCK_OFFSET = -1;
@@ -672,7 +679,10 @@
int moveExceptionDest = source.getMoveExceptionRegister(targetIndex);
Position position = source.getCanonicalDebugPositionAtOffset(moveExceptionItem.targetOffset);
if (moveExceptionDest >= 0) {
- Value out = writeRegister(moveExceptionDest, ValueType.OBJECT, ThrowingInfo.NO_THROW, null);
+ Set<DexType> exceptionTypes = MoveException.collectExceptionTypes(currentBlock, getFactory());
+ TypeLatticeElement typeLattice = TypeLatticeElement.join(appInfo,
+ exceptionTypes.stream().map(t -> TypeLatticeElement.fromDexType(t, appInfo, false)));
+ Value out = writeRegister(moveExceptionDest, typeLattice, ThrowingInfo.NO_THROW, null);
MoveException moveException = new MoveException(out);
moveException.setPosition(position);
currentBlock.add(moveException);
@@ -719,20 +729,23 @@
public void addThisArgument(int register) {
DebugLocalInfo local = getOutgoingLocal(register);
- Value value = writeRegister(register, ValueType.OBJECT, ThrowingInfo.NO_THROW, local);
+ // TODO(b/72693244): Update nullability if this is for building inlinee's IR.
+ TypeLatticeElement receiver =
+ TypeLatticeElement.fromDexType(method.method.getHolder(), appInfo, false);
+ Value value = writeRegister(register, receiver, ThrowingInfo.NO_THROW, local);
addInstruction(new Argument(value));
value.markAsThis();
}
- public void addNonThisArgument(int register, ValueType valueType) {
+ public void addNonThisArgument(int register, TypeLatticeElement typeLattice) {
DebugLocalInfo local = getOutgoingLocal(register);
- Value value = writeRegister(register, valueType, ThrowingInfo.NO_THROW, local);
+ Value value = writeRegister(register, typeLattice, ThrowingInfo.NO_THROW, local);
addInstruction(new Argument(value));
}
public void addBooleanNonThisArgument(int register) {
DebugLocalInfo local = getOutgoingLocal(register);
- Value value = writeRegister(register, ValueType.INT, ThrowingInfo.NO_THROW, local);
+ Value value = writeRegister(register, INT, ThrowingInfo.NO_THROW, local);
value.setKnownToBeBoolean(true);
addInstruction(new Argument(value));
}
@@ -756,7 +769,8 @@
// Note that the write register must not lookup outgoing local information and the local is
// never considered clobbered by a start (if the in value has local info it must have been
// marked ended elsewhere).
- Value out = writeRegister(register, incomingValue.outType(), ThrowingInfo.NO_THROW, local);
+ Value out = writeRegister(
+ register, incomingValue.getTypeLattice(), ThrowingInfo.NO_THROW, local);
DebugLocalWrite write = new DebugLocalWrite(out, incomingValue);
addInstruction(write);
}
@@ -831,7 +845,8 @@
public void addArrayGet(MemberType type, int dest, int array, int index) {
Value in1 = readRegister(array, ValueType.OBJECT);
Value in2 = readRegister(index, ValueType.INT);
- Value out = writeRegister(dest, ValueType.fromMemberType(type), ThrowingInfo.CAN_THROW);
+ Value out = writeRegister(
+ dest, TypeLatticeElement.fromMemberType(type), ThrowingInfo.CAN_THROW);
out.setKnownToBeBoolean(type == MemberType.BOOLEAN);
ArrayGet instruction = new ArrayGet(type, out, in1, in2);
assert instruction.instructionTypeCanThrow();
@@ -840,7 +855,7 @@
public void addArrayLength(int dest, int array) {
Value in = readRegister(array, ValueType.OBJECT);
- Value out = writeRegister(dest, ValueType.INT, ThrowingInfo.CAN_THROW);
+ Value out = writeRegister(dest, INT, ThrowingInfo.CAN_THROW);
ArrayLength instruction = new ArrayLength(out, in);
assert instruction.instructionTypeCanThrow();
add(instruction);
@@ -856,7 +871,9 @@
public void addCheckCast(int value, DexType type) {
Value in = readRegister(value, ValueType.OBJECT);
- Value out = writeRegister(value, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
+ TypeLatticeElement castTypeLattice =
+ TypeLatticeElement.fromDexType(type, appInfo, in.getTypeLattice().isNullable());
+ Value out = writeRegister(value, castTypeLattice, ThrowingInfo.CAN_THROW);
CheckCast instruction = new CheckCast(out, in, type);
assert instruction.instructionTypeCanThrow();
add(instruction);
@@ -865,41 +882,42 @@
public void addCmp(NumericType type, Bias bias, int dest, int left, int right) {
Value in1 = readNumericRegister(left, type);
Value in2 = readNumericRegister(right, type);
- Value out = writeRegister(dest, ValueType.INT, ThrowingInfo.NO_THROW);
+ Value out = writeRegister(dest, INT, ThrowingInfo.NO_THROW);
Cmp instruction = new Cmp(type, bias, out, in1, in2);
assert !instruction.instructionTypeCanThrow();
add(instruction);
}
- public void addConst(ValueType type, int dest, long value) {
- Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
+ public void addConst(TypeLatticeElement typeLattice, int dest, long value) {
+ Value out = writeRegister(dest, typeLattice, ThrowingInfo.NO_THROW);
ConstNumber instruction = new ConstNumber(out, value);
assert !instruction.instructionTypeCanThrow();
add(instruction);
}
public void addLongConst(int dest, long value) {
- add(new ConstNumber(writeRegister(dest, ValueType.LONG, ThrowingInfo.NO_THROW), value));
+ add(new ConstNumber(writeRegister(dest, LONG, ThrowingInfo.NO_THROW), value));
}
public void addDoubleConst(int dest, long value) {
- add(new ConstNumber(writeRegister(dest, ValueType.DOUBLE, ThrowingInfo.NO_THROW), value));
+ add(new ConstNumber(writeRegister(dest, DOUBLE, ThrowingInfo.NO_THROW), value));
}
public void addIntConst(int dest, long value) {
- add(new ConstNumber(writeRegister(dest, ValueType.INT, ThrowingInfo.NO_THROW), value));
+ add(new ConstNumber(writeRegister(dest, INT, ThrowingInfo.NO_THROW), value));
}
public void addFloatConst(int dest, long value) {
- add(new ConstNumber(writeRegister(dest, ValueType.FLOAT, ThrowingInfo.NO_THROW), value));
+ add(new ConstNumber(writeRegister(dest, FLOAT, ThrowingInfo.NO_THROW), value));
}
public void addNullConst(int dest) {
- add(new ConstNumber(writeRegister(dest, ValueType.OBJECT, ThrowingInfo.NO_THROW), 0L));
+ add(new ConstNumber(writeRegister(dest, NULL, ThrowingInfo.NO_THROW), 0L));
}
public void addConstClass(int dest, DexType type) {
- Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
+ TypeLatticeElement typeLattice = TypeLatticeElement.classClassType(appInfo);
+ Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
ConstClass instruction = new ConstClass(out, type);
assert instruction.instructionTypeCanThrow();
add(instruction);
@@ -912,7 +930,9 @@
"Const-method-handle",
null /* sourceString */);
}
- Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
+ TypeLatticeElement typeLattice =
+ TypeLatticeElement.fromDexType(appInfo.dexItemFactory.methodHandleType, appInfo, false);
+ Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
ConstMethodHandle instruction = new ConstMethodHandle(out, methodHandle);
add(instruction);
}
@@ -924,13 +944,16 @@
"Const-method-type",
null /* sourceString */);
}
- Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
+ TypeLatticeElement typeLattice =
+ TypeLatticeElement.fromDexType(appInfo.dexItemFactory.methodTypeType, appInfo, false);
+ Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
ConstMethodType instruction = new ConstMethodType(out, methodType);
add(instruction);
}
public void addConstString(int dest, DexString string) {
- Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
+ TypeLatticeElement typeLattice = TypeLatticeElement.stringClassType(appInfo);
+ Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
ConstString instruction = new ConstString(out, string);
add(instruction);
}
@@ -971,7 +994,7 @@
// If the move is writing to a different local we must construct a new value.
DebugLocalInfo destLocal = getOutgoingLocal(dest);
if (destLocal != null && destLocal != in.getLocalInfo()) {
- Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
+ Value out = writeRegister(dest, in.getTypeLattice(), ThrowingInfo.NO_THROW);
addInstruction(new DebugLocalWrite(out, in));
return;
}
@@ -1067,7 +1090,8 @@
}
}
- public void addIfZero(If.Type type, ValueType operandType, int value, int trueTargetOffset, int falseTargetOffset) {
+ public void addIfZero(
+ If.Type type, ValueType operandType, int value, int trueTargetOffset, int falseTargetOffset) {
if (trueTargetOffset == falseTargetOffset) {
addTrivialIf(trueTargetOffset, falseTargetOffset);
} else {
@@ -1079,7 +1103,8 @@
public void addInstanceGet(int dest, int object, DexField field) {
MemberType type = MemberType.fromDexType(field.type);
Value in = readRegister(object, ValueType.OBJECT);
- Value out = writeRegister(dest, ValueType.fromMemberType(type), ThrowingInfo.CAN_THROW);
+ Value out = writeRegister(
+ dest, TypeLatticeElement.fromDexType(field.type, appInfo, true), ThrowingInfo.CAN_THROW);
out.setKnownToBeBoolean(type == MemberType.BOOLEAN);
InstanceGet instruction = new InstanceGet(type, out, in, field);
assert instruction.instructionTypeCanThrow();
@@ -1088,7 +1113,7 @@
public void addInstanceOf(int dest, int value, DexType type) {
Value in = readRegister(value, ValueType.OBJECT);
- Value out = writeRegister(dest, ValueType.INT, ThrowingInfo.CAN_THROW);
+ Value out = writeRegister(dest, INT, ThrowingInfo.CAN_THROW);
InstanceOf instruction = new InstanceOf(out, in, type);
assert instruction.instructionTypeCanThrow();
addInstruction(instruction);
@@ -1359,7 +1384,8 @@
assert invoke.outValue() == null;
assert invoke.instructionTypeCanThrow();
DexType outType = invoke.getReturnType();
- Value outValue = writeRegister(dest, ValueType.fromDexType(outType), ThrowingInfo.CAN_THROW);
+ Value outValue =
+ writeRegister(dest, TypeLatticeElement.fromDexType(outType), ThrowingInfo.CAN_THROW);
outValue.setKnownToBeBoolean(outType.isBooleanType());
invoke.setOutValue(outValue);
}
@@ -1389,7 +1415,8 @@
public void addNewArrayEmpty(int dest, int size, DexType type) {
assert type.isArrayType();
Value in = readRegister(size, ValueType.INT);
- Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
+ TypeLatticeElement arrayTypeLattice = TypeLatticeElement.fromDexType(type, appInfo, false);
+ Value out = writeRegister(dest, arrayTypeLattice, ThrowingInfo.CAN_THROW);
NewArrayEmpty instruction = new NewArrayEmpty(out, in, type);
assert instruction.instructionTypeCanThrow();
addInstruction(instruction);
@@ -1400,7 +1427,8 @@
}
public void addNewInstance(int dest, DexType type) {
- Value out = writeRegister(dest, ValueType.OBJECT, ThrowingInfo.CAN_THROW);
+ TypeLatticeElement instanceType = TypeLatticeElement.fromDexType(type, appInfo, false);
+ Value out = writeRegister(dest, instanceType, ThrowingInfo.CAN_THROW);
NewInstance instruction = new NewInstance(type, out);
assert instruction.instructionTypeCanThrow();
addInstruction(instruction);
@@ -1426,7 +1454,8 @@
public void addStaticGet(int dest, DexField field) {
MemberType type = MemberType.fromDexType(field.type);
- Value out = writeRegister(dest, ValueType.fromMemberType(type), ThrowingInfo.CAN_THROW);
+ Value out = writeRegister(
+ dest, TypeLatticeElement.fromDexType(field.type, appInfo, true), ThrowingInfo.CAN_THROW);
out.setKnownToBeBoolean(type == MemberType.BOOLEAN);
StaticGet instruction = new StaticGet(type, out, field);
assert instruction.instructionTypeCanThrow();
@@ -1683,8 +1712,8 @@
public Value readRegister(int register, ValueType type) {
DebugLocalInfo local = getIncomingLocal(register);
- Value value =
- readRegister(register, type, currentBlock, EdgeType.NON_EDGE, RegisterReadType.NORMAL);
+ Value value = readRegister(
+ register, type, currentBlock, EdgeType.NON_EDGE, RegisterReadType.NORMAL);
// Check that any information about a current-local is consistent with the read.
if (local != null && value.getLocalInfo() != local && !value.isUninitializedLocal()) {
throw new InvalidDebugInfoException(
@@ -1759,7 +1788,9 @@
value = getUninitializedDebugLocalValue(register, type);
} else {
DebugLocalInfo local = getIncomingLocalAtBlock(register, block);
- Phi phi = new Phi(valueNumberGenerator.next(), block, type, local, readType);
+ // TODO(b/72693244): Use BOTTOM, then run type analysis at the end of IR building.
+ Phi phi = new Phi(
+ valueNumberGenerator.next(), block, type.toTypeLattice(), local, readType);
if (!block.isSealed()) {
block.addIncompletePhi(register, phi, readingEdge);
value = phi;
@@ -1811,7 +1842,7 @@
// Create a new SSA value for the uninitialized local value.
// Note that the uninitialized local value must not itself have local information, so that it
// does not contribute to the visible/live-range of the local variable.
- Value value = new Value(valueNumberGenerator.next(), type, null);
+ Value value = new Value(valueNumberGenerator.next(), type.toTypeLattice(), null);
values.add(value);
return value;
}
@@ -1830,14 +1861,14 @@
}
public Value readLongLiteral(long constant) {
- Value value = new Value(valueNumberGenerator.next(), ValueType.LONG, null);
+ Value value = new Value(valueNumberGenerator.next(), LONG, null);
ConstNumber number = new ConstNumber(value, constant);
add(number);
return number.outValue();
}
public Value readIntLiteral(long constant) {
- Value value = new Value(valueNumberGenerator.next(), ValueType.INT, null);
+ Value value = new Value(valueNumberGenerator.next(), INT, null);
ConstNumber number = new ConstNumber(value, constant);
add(number);
return number.outValue();
@@ -1846,14 +1877,14 @@
// This special write register is needed when changing the scoping of a local variable.
// See addDebugLocalStart and addDebugLocalEnd.
private Value writeRegister(
- int register, ValueType type, ThrowingInfo throwing, DebugLocalInfo local) {
+ int register, TypeLatticeElement typeLattice, ThrowingInfo throwing, DebugLocalInfo local) {
checkRegister(register);
- Value value = new Value(valueNumberGenerator.next(), type, local);
+ Value value = new Value(valueNumberGenerator.next(), typeLattice, local);
currentBlock.writeCurrentDefinition(register, value, throwing);
return value;
}
- public Value writeRegister(int register, ValueType type, ThrowingInfo throwing) {
+ public Value writeRegister(int register, TypeLatticeElement typeLattice, ThrowingInfo throwing) {
DebugLocalInfo incomingLocal = getIncomingLocal(register);
DebugLocalInfo outgoingLocal = getOutgoingLocal(register);
// If the local info does not change at the current instruction, we need to ensure
@@ -1868,11 +1899,11 @@
(incomingLocal == null || incomingLocal != outgoingLocal)
? null
: readRegisterForDebugLocal(register, incomingLocal);
- return writeRegister(register, type, throwing, outgoingLocal);
+ return writeRegister(register, typeLattice, throwing, outgoingLocal);
}
public Value writeNumericRegister(int register, NumericType type, ThrowingInfo throwing) {
- return writeRegister(register, ValueType.fromNumericType(type), throwing);
+ return writeRegister(register, PrimitiveTypeLatticeElement.fromNumericType(type), throwing);
}
private DebugLocalInfo getIncomingLocal(int register) {
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 db0c983..3c657ec 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
@@ -27,6 +27,7 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.ir.analysis.constant.SparseConditionalConstantPropagation;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.AlwaysMaterializingDefinition;
import com.android.tools.r8.ir.code.AlwaysMaterializingUser;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -34,7 +35,6 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
@@ -143,7 +143,7 @@
this.options = options;
this.printer = printer;
this.codeRewriter = new CodeRewriter(this, libraryMethodsReturningReceiver(), options);
- this.stringConcatRewriter = new StringConcatRewriter(options.itemFactory);
+ this.stringConcatRewriter = new StringConcatRewriter(appInfo);
this.lambdaRewriter = options.enableDesugaring ? new LambdaRewriter(this) : null;
this.interfaceMethodRewriter =
(options.enableDesugaring && enableInterfaceMethodDesugaring())
@@ -151,8 +151,8 @@
this.twrCloseResourceRewriter =
(options.enableDesugaring && enableTwrCloseResourceDesugaring())
? new TwrCloseResourceRewriter(this) : null;
- this.lambdaMerger = options.enableLambdaMerging
- ? new LambdaMerger(appInfo.dexItemFactory, options.reporter) : null;
+ this.lambdaMerger =
+ options.enableLambdaMerging ? new LambdaMerger(appInfo, options.reporter) : null;
this.covariantReturnTypeAnnotationTransformer =
options.processCovariantReturnTypeAnnotations
? new CovariantReturnTypeAnnotationTransformer(this, appInfo.dexItemFactory)
@@ -790,6 +790,9 @@
if (devirtualizer != null) {
devirtualizer.devirtualizeInvokeInterface(code, method.method.getHolder());
}
+
+ assert code.verifyTypes(appInfo);
+
codeRewriter.removeCasts(code);
codeRewriter.rewriteLongCompareAndRequireNonNull(code, options);
codeRewriter.commonSubexpressionElimination(code);
@@ -834,6 +837,8 @@
assert code.isConsistentSSA();
}
+ assert code.verifyTypes(appInfo);
+
if (classInliner != null) {
// Class inliner should work before lambda merger, so if it inlines the
// lambda, it does not get collected by merger.
@@ -962,7 +967,7 @@
private void finalizeToDex(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
// Workaround massive dex2oat memory use for self-recursive methods.
- CodeRewriter.disableDex2OatInliningForSelfRecursiveMethods(code, options);
+ CodeRewriter.disableDex2OatInliningForSelfRecursiveMethods(code, options, appInfo);
// Perform register allocation.
RegisterAllocator registerAllocator = performRegisterAllocation(code, method);
method.setCode(code, registerAllocator, options);
@@ -1075,7 +1080,7 @@
Instruction check = it.previous();
assert addBefore == check;
// Forced definition of const-zero
- Value fixitValue = code.createValue(ValueType.INT);
+ Value fixitValue = code.createValue(TypeLatticeElement.INT);
Instruction fixitDefinition = new AlwaysMaterializingDefinition(fixitValue);
fixitDefinition.setBlock(addBefore.getBlock());
fixitDefinition.setPosition(addBefore.getPosition());
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 d17233f..22a5bc2 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
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.JarApplicationReader;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Cmp.Bias;
import com.android.tools.r8.ir.code.If;
@@ -278,28 +279,29 @@
state.beginTransactionSynthetic();
// Record types for arguments.
- Int2ReferenceMap<ValueType> argumentLocals = recordArgumentTypes();
- Int2ReferenceMap<ValueType> initializedLocals = new Int2ReferenceOpenHashMap<>(argumentLocals);
+ Int2ReferenceMap<TypeLatticeElement> argumentLocals = recordArgumentTypes(builder);
+ Int2ReferenceMap<TypeLatticeElement> initializedLocals =
+ new Int2ReferenceOpenHashMap<>(argumentLocals);
// Initialize all non-argument locals to ensure safe insertion of debug-local instructions.
for (Object o : node.localVariables) {
LocalVariableNode local = (LocalVariableNode) o;
Type localType;
- ValueType localValueType;
+ TypeLatticeElement localValueTypeLattice;
switch (application.getAsmType(local.desc).getSort()) {
case Type.OBJECT:
case Type.ARRAY: {
localType = JarState.NULL_TYPE;
- localValueType = ValueType.OBJECT;
+ localValueTypeLattice = TypeLatticeElement.REFERENCE;
break;
}
case Type.LONG: {
localType = Type.LONG_TYPE;
- localValueType = ValueType.LONG;
+ localValueTypeLattice = TypeLatticeElement.LONG;
break;
}
case Type.DOUBLE: {
localType = Type.DOUBLE_TYPE;
- localValueType = ValueType.DOUBLE;
+ localValueTypeLattice = TypeLatticeElement.DOUBLE;
break;
}
case Type.BOOLEAN:
@@ -308,12 +310,12 @@
case Type.SHORT:
case Type.INT: {
localType = Type.INT_TYPE;
- localValueType = ValueType.INT;
+ localValueTypeLattice = TypeLatticeElement.INT;
break;
}
case Type.FLOAT: {
localType = Type.FLOAT_TYPE;
- localValueType = ValueType.FLOAT;
+ localValueTypeLattice = TypeLatticeElement.FLOAT;
break;
}
case Type.VOID:
@@ -322,11 +324,11 @@
throw new Unreachable("Invalid local variable type: " );
}
int localRegister = state.getLocalRegister(local.index, localType);
- ValueType existingLocalType = initializedLocals.get(localRegister);
- if (existingLocalType == null) {
+ TypeLatticeElement existingLocalTypeLattice = initializedLocals.get(localRegister);
+ if (existingLocalTypeLattice == null) {
int writeRegister = state.writeLocal(local.index, localType);
assert writeRegister == localRegister;
- initializedLocals.put(localRegister, localValueType);
+ initializedLocals.put(localRegister, localValueTypeLattice);
}
}
@@ -375,31 +377,31 @@
builder.addThisArgument(slot.register);
}
for (Type type : parameterTypes) {
- ValueType valueType = valueType(type);
+ TypeLatticeElement typeLattice = typeLattice(type);
Slot slot = state.readLocal(argumentRegister, type);
if (type == Type.BOOLEAN_TYPE) {
builder.addBooleanNonThisArgument(slot.register);
} else {
- builder.addNonThisArgument(slot.register, valueType);
+ builder.addNonThisArgument(slot.register, typeLattice);
}
- argumentRegister += valueType.requiredRegisters();
+ argumentRegister += typeLattice.requiredRegisters();
}
}
- private Int2ReferenceMap<ValueType> recordArgumentTypes() {
- Int2ReferenceMap<ValueType> initializedLocals =
+ private Int2ReferenceMap<TypeLatticeElement> recordArgumentTypes(IRBuilder builder) {
+ Int2ReferenceMap<TypeLatticeElement> initializedLocals =
new Int2ReferenceOpenHashMap<>(node.localVariables.size());
int argumentRegister = 0;
if (!isStatic()) {
Type thisType = application.getAsmType(clazz.descriptor.toString());
int register = state.writeLocal(argumentRegister++, thisType);
- initializedLocals.put(register, valueType(thisType));
+ initializedLocals.put(register, typeLattice(thisType));
}
for (Type type : parameterTypes) {
- ValueType valueType = valueType(type);
+ TypeLatticeElement typeLattice = typeLattice(type);
int register = state.writeLocal(argumentRegister, type);
- argumentRegister += valueType.requiredRegisters();
- initializedLocals.put(register, valueType);
+ argumentRegister += typeLattice.requiredRegisters();
+ initializedLocals.put(register, typeLattice);
}
return initializedLocals;
}
@@ -937,6 +939,10 @@
}
}
+ private static TypeLatticeElement typeLattice(Type type) {
+ return valueType(type).toTypeLattice();
+ }
+
private static MemberType memberType(Type type) {
switch (type.getSort()) {
case Type.ARRAY:
@@ -2691,7 +2697,10 @@
}
}
- private static void addArgument(List<ValueType> types, List<Integer> registers, Type type,
+ private static void addArgument(
+ List<ValueType> types,
+ List<Integer> registers,
+ Type type,
Slot slot) {
assert slot.isCompatibleWith(type);
types.add(valueType(type));
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 283c163..d3b57cd 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -46,10 +46,12 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.VerticalClassMerger.VerticallyMergedClasses;
import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class LensCodeRewriter {
@@ -69,18 +71,24 @@
this.options = options;
}
- private Value makeOutValue(Instruction insn, IRCode code) {
+ private Value makeOutValue(
+ Instruction insn,
+ IRCode code,
+ ImmutableSet.Builder<Value> collector) {
if (insn.outValue() == null) {
return null;
} else {
- return code.createValue(insn.outType(), insn.getLocalInfo());
+ Value newValue = code.createValue(insn.outValue().getTypeLattice(), insn.getLocalInfo());
+ collector.add(newValue);
+ return newValue;
}
}
/**
* Replace type appearances, invoke targets and field accesses with actual definitions.
*/
- public void rewrite(IRCode code, DexEncodedMethod method) {
+ public Set<Value> rewrite(IRCode code, DexEncodedMethod method) {
+ ImmutableSet.Builder<Value> valueCollector = ImmutableSet.builder();
ListIterator<BasicBlock> blocks = code.blocks.listIterator();
while (blocks.hasNext()) {
BasicBlock block = blocks.next();
@@ -118,9 +126,7 @@
handle, method, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY);
if (newHandle != handle) {
ConstMethodHandle newInstruction =
- new ConstMethodHandle(
- code.createValue(current.outType(), current.getLocalInfo()),
- newHandle);
+ new ConstMethodHandle(makeOutValue(current, code, valueCollector), newHandle);
iterator.replaceCurrentInstruction(newInstruction);
}
} else if (current.isInvokeMethod()) {
@@ -144,7 +150,7 @@
// Fix up the return type if needed.
if (actualTarget.proto.returnType != invokedMethod.proto.returnType
&& newInvoke.outValue() != null) {
- Value newValue = code.createValue(newInvoke.outType(), invoke.getLocalInfo());
+ Value newValue = makeOutValue(newInvoke, code, valueCollector);
newInvoke.outValue().replaceUsers(newValue);
CheckCast cast =
new CheckCast(
@@ -202,60 +208,66 @@
CheckCast checkCast = current.asCheckCast();
DexType newType = graphLense.lookupType(checkCast.getType());
if (newType != checkCast.getType()) {
- CheckCast newCheckCast =
- new CheckCast(makeOutValue(checkCast, code), checkCast.object(), newType);
+ CheckCast newCheckCast = new CheckCast(
+ makeOutValue(checkCast, code, valueCollector), checkCast.object(), newType);
iterator.replaceCurrentInstruction(newCheckCast);
}
} else if (current.isConstClass()) {
ConstClass constClass = current.asConstClass();
DexType newType = graphLense.lookupType(constClass.getValue());
if (newType != constClass.getValue()) {
- ConstClass newConstClass = new ConstClass(makeOutValue(constClass, code), newType);
+ ConstClass newConstClass = new ConstClass(
+ makeOutValue(constClass, code, valueCollector), newType);
iterator.replaceCurrentInstruction(newConstClass);
}
} else if (current.isInstanceOf()) {
InstanceOf instanceOf = current.asInstanceOf();
DexType newType = graphLense.lookupType(instanceOf.type());
if (newType != instanceOf.type()) {
- InstanceOf newInstanceOf = new InstanceOf(makeOutValue(instanceOf, code),
- instanceOf.value(), newType);
+ InstanceOf newInstanceOf = new InstanceOf(
+ makeOutValue(instanceOf, code, valueCollector), instanceOf.value(), newType);
iterator.replaceCurrentInstruction(newInstanceOf);
}
} else if (current.isInvokeMultiNewArray()) {
InvokeMultiNewArray multiNewArray = current.asInvokeMultiNewArray();
DexType newType = graphLense.lookupType(multiNewArray.getArrayType());
if (newType != multiNewArray.getArrayType()) {
- InvokeMultiNewArray newMultiNewArray = new InvokeMultiNewArray(
- newType, makeOutValue(multiNewArray, code), multiNewArray.inValues());
+ InvokeMultiNewArray newMultiNewArray =
+ new InvokeMultiNewArray(
+ newType,
+ makeOutValue(multiNewArray, code, valueCollector),
+ multiNewArray.inValues());
iterator.replaceCurrentInstruction(newMultiNewArray);
}
} else if (current.isInvokeNewArray()) {
InvokeNewArray newArray = current.asInvokeNewArray();
DexType newType = graphLense.lookupType(newArray.getArrayType());
if (newType != newArray.getArrayType()) {
- InvokeNewArray newNewArray = new InvokeNewArray(newType, makeOutValue(newArray, code),
- newArray.inValues());
+ InvokeNewArray newNewArray = new InvokeNewArray(
+ newType, makeOutValue(newArray, code, valueCollector), newArray.inValues());
iterator.replaceCurrentInstruction(newNewArray);
}
} else if (current.isNewArrayEmpty()) {
NewArrayEmpty newArrayEmpty = current.asNewArrayEmpty();
DexType newType = graphLense.lookupType(newArrayEmpty.type);
if (newType != newArrayEmpty.type) {
- NewArrayEmpty newNewArray = new NewArrayEmpty(makeOutValue(newArrayEmpty, code),
- newArrayEmpty.size(), newType);
+ NewArrayEmpty newNewArray = new NewArrayEmpty(
+ makeOutValue(newArrayEmpty, code, valueCollector), newArrayEmpty.size(), newType);
iterator.replaceCurrentInstruction(newNewArray);
}
} else if (current.isNewInstance()) {
NewInstance newInstance= current.asNewInstance();
DexType newClazz = graphLense.lookupType(newInstance.clazz);
if (newClazz != newInstance.clazz) {
- NewInstance newNewInstance = new NewInstance(newClazz, makeOutValue(newInstance, code));
+ NewInstance newNewInstance = new NewInstance(
+ newClazz, makeOutValue(newInstance, code, valueCollector));
iterator.replaceCurrentInstruction(newNewInstance);
}
}
}
}
assert code.isConsistentSSA();
+ return valueCollector.build();
}
// If the given invoke is on the form "invoke-direct A.<init>, v0, ..." and the definition of
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
index ccccb21..2aa4630 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import java.util.Collections;
+import com.google.common.collect.ImmutableList;
// Source code representing synthesized lambda class constructor.
// Used for stateless lambdas to instantiate singleton instance.
@@ -25,8 +25,11 @@
int instance = nextRegister(ValueType.OBJECT);
add(builder -> builder.addNewInstance(instance, lambda.type));
add(builder -> builder.addInvoke(
- Invoke.Type.DIRECT, lambda.constructor, lambda.constructor.proto,
- Collections.singletonList(ValueType.OBJECT), Collections.singletonList(instance)));
+ Invoke.Type.DIRECT,
+ lambda.constructor,
+ lambda.constructor.proto,
+ ImmutableList.of(ValueType.OBJECT),
+ ImmutableList.of(instance)));
// Assign to a field.
add(builder -> builder.addStaticPut(instance, lambda.instanceField));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index 9d815ce..872f7ac 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
@@ -479,7 +480,7 @@
private int addPrimitiveUnboxing(int register, DexType primitiveType, DexType boxType) {
DexMethod method = getUnboxMethod(primitiveType.descriptor.content[0], boxType);
- List<ValueType> argValueTypes = Collections.singletonList(ValueType.OBJECT);
+ List<ValueType> argValueTypes = ImmutableList.of(ValueType.OBJECT);
List<Integer> argRegisters = Collections.singletonList(register);
add(builder -> builder.addInvoke(Invoke.Type.VIRTUAL,
method, method.proto, argValueTypes, argRegisters));
@@ -502,7 +503,7 @@
DexMethod method = factory.createMethod(boxType, proto, factory.valueOfMethodName);
ValueType valueType = ValueType.fromDexType(primitiveType);
- List<ValueType> argValueTypes = Collections.singletonList(valueType);
+ List<ValueType> argValueTypes = ImmutableList.of(valueType);
List<Integer> argRegisters = Collections.singletonList(register);
add(builder -> builder.addInvoke(Invoke.Type.STATIC,
method, method.proto, argValueTypes, argRegisters));
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 9d475c3..129ed58 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
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -25,7 +26,6 @@
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
@@ -276,7 +276,8 @@
Value lambdaInstanceValue = invoke.outValue();
if (lambdaInstanceValue == null) {
// The out value might be empty in case it was optimized out.
- lambdaInstanceValue = code.createValue(ValueType.OBJECT);
+ lambdaInstanceValue = code.createValue(
+ TypeLatticeElement.fromDexType(lambdaClass.type, appInfo, true));
}
// For stateless lambdas we replace InvokeCustom instruction with StaticGet
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
index 399ae92..c805494 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
@@ -6,12 +6,14 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.IRCode;
@@ -22,7 +24,6 @@
import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
@@ -43,6 +44,7 @@
private static final String TO_STRING = "toString";
private static final String APPEND = "append";
+ private final AppInfo appInfo;
private final DexItemFactory factory;
private final DexMethod makeConcat;
@@ -54,9 +56,10 @@
private final Map<DexType, DexMethod> paramTypeToAppendMethod = new IdentityHashMap<>();
private final DexMethod defaultAppendMethod;
- public StringConcatRewriter(DexItemFactory factory) {
- assert factory != null;
- this.factory = factory;
+ public StringConcatRewriter(AppInfo appInfo) {
+ this.appInfo = appInfo;
+ assert appInfo.dexItemFactory != null;
+ this.factory = appInfo.dexItemFactory;
DexType factoryType = factory.createType(CONCAT_FACTORY_TYPE_DESCR);
DexType callSiteType = factory.createType(CALLSITE_TYPE_DESCR);
@@ -159,7 +162,7 @@
}
// Collect chunks.
- ConcatBuilder builder = new ConcatBuilder(code, blocks, instructions);
+ ConcatBuilder builder = new ConcatBuilder(appInfo, code, blocks, instructions);
for (int i = 0; i < paramCount; i++) {
builder.addChunk(arguments.get(i),
paramTypeToAppendMethod.getOrDefault(parameters[i], defaultAppendMethod));
@@ -214,7 +217,7 @@
String recipe = ((DexValue.DexValueString) recipeValue).getValue().toString();
// Collect chunks and patch the instruction.
- ConcatBuilder builder = new ConcatBuilder(code, blocks, instructions);
+ ConcatBuilder builder = new ConcatBuilder(appInfo, code, blocks, instructions);
StringBuilder acc = new StringBuilder();
int argIndex = 0;
int constArgIndex = 0;
@@ -276,6 +279,7 @@
}
private final class ConcatBuilder {
+ private final AppInfo appInfo;
private final IRCode code;
private final ListIterator<BasicBlock> blocks;
private final InstructionListIterator instructions;
@@ -284,7 +288,11 @@
private final List<Chunk> chunks = new ArrayList<>();
private ConcatBuilder(
- IRCode code, ListIterator<BasicBlock> blocks, InstructionListIterator instructions) {
+ AppInfo appInfo,
+ IRCode code,
+ ListIterator<BasicBlock> blocks,
+ InstructionListIterator instructions) {
+ this.appInfo = appInfo;
this.code = code;
this.blocks = blocks;
this.instructions = instructions;
@@ -328,7 +336,9 @@
instructions.previous();
// new-instance v0, StringBuilder
- Value sbInstance = code.createValue(ValueType.OBJECT);
+ TypeLatticeElement stringBuilderTypeLattice =
+ TypeLatticeElement.fromDexType(factory.stringBuilderType, appInfo, false);
+ Value sbInstance = code.createValue(stringBuilderTypeLattice);
appendInstruction(new NewInstance(factory.stringBuilderType, sbInstance));
// invoke-direct {v0}, void StringBuilder.<init>()
@@ -349,7 +359,7 @@
Value concatValue = invokeCustom.outValue();
if (concatValue == null) {
// The out value might be empty in case it was optimized out.
- concatValue = code.createValue(ValueType.OBJECT);
+ concatValue = code.createValue(TypeLatticeElement.stringClassType(appInfo));
}
// Replace the instruction.
@@ -427,7 +437,7 @@
@Override
Value getOrCreateValue() {
- Value value = code.createValue(ValueType.OBJECT);
+ Value value = code.createValue(TypeLatticeElement.stringClassType(appInfo));
appendInstruction(new ConstString(value, factory.createString(str)));
return value;
}
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 67b6e2d..f8b85de 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
@@ -76,7 +76,6 @@
import com.android.tools.r8.ir.code.Switch;
import com.android.tools.r8.ir.code.Throw;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.code.Xor;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.OptimizationFeedback;
@@ -270,7 +269,7 @@
// For method with many self-recursive calls, insert a try-catch to disable inlining.
// Marshmallow dex2oat aggressively inlines and eats up all the memory on devices.
public static void disableDex2OatInliningForSelfRecursiveMethods(
- IRCode code, InternalOptions options) {
+ IRCode code, InternalOptions options, AppInfo appInfo) {
if (!options.canHaveDex2OatInliningIssue() || code.hasCatchHandlers()) {
// Catch handlers disables inlining, so if the method already has catch handlers
// there is nothing to do.
@@ -294,11 +293,14 @@
splitIterator.previous();
BasicBlock newBlock = splitIterator.split(code, 1);
// Generate rethrow block.
- BasicBlock rethrowBlock =
- BasicBlock.createRethrowBlock(code, lastSelfRecursiveCall.getPosition());
+ DexType guard = options.itemFactory.throwableType;
+ BasicBlock rethrowBlock = BasicBlock.createRethrowBlock(
+ code,
+ lastSelfRecursiveCall.getPosition(),
+ TypeLatticeElement.fromDexType(guard, appInfo, true));
code.blocks.add(rethrowBlock);
// Add catch handler to the block containing the last recursive call.
- newBlock.addCatchHandler(rethrowBlock, options.itemFactory.throwableType);
+ newBlock.addCatchHandler(rethrowBlock, guard);
}
}
@@ -1649,35 +1651,39 @@
&& outValue.isUsed()
&& outValue.numberOfPhiUsers() == 0
&& outValue.uniqueUsers().stream().allMatch(isCheckcastToSubtype)) {
- removeOrReplaceByDebugLocalWrite(it, inValue, outValue);
+ removeOrReplaceByDebugLocalWrite(checkCast, it, inValue, outValue);
continue;
}
TypeLatticeElement inTypeLattice = inValue.getTypeLattice();
- // TODO(b/72693244): Soon, there won't be a value with Bottom at this point.
- if (!inTypeLattice.isBottom()) {
+ // TODO(b/72693244): Soon, there won't be a value with imprecise type at this point.
+ if (inTypeLattice.isPreciseType() || inTypeLattice.isNull()) {
TypeLatticeElement outTypeLattice = outValue.getTypeLattice();
TypeLatticeElement castTypeLattice =
- TypeLatticeElement.fromDexType(appInfo, castType, inTypeLattice.isNullable());
- // 1) Trivial cast.
- // A a = ...
- // A a' = (A) a;
- // 2) Up-cast: we already have finer type info.
- // A < B
- // A a = ...
- // B b = (B) a;
+ TypeLatticeElement.fromDexType(castType, appInfo, inTypeLattice.isNullable());
+
+ assert inTypeLattice.nullElement().lessThanOrEqual(outTypeLattice.nullElement());
+
if (TypeLatticeElement.lessThanOrEqual(appInfo, inTypeLattice, castTypeLattice)) {
- assert outTypeLattice.equals(inTypeLattice);
+ // 1) Trivial cast.
+ // A a = ...
+ // A a' = (A) a;
+ // 2) Up-cast: we already have finer type info.
+ // A < B
+ // A a = ...
+ // B b = (B) a;
+ assert TypeLatticeElement.lessThanOrEqual(appInfo, inTypeLattice, outTypeLattice);
needToRemoveTrivialPhis = needToRemoveTrivialPhis || outValue.numberOfPhiUsers() != 0;
- removeOrReplaceByDebugLocalWrite(it, inValue, outValue);
- continue;
+ removeOrReplaceByDebugLocalWrite(checkCast, it, inValue, outValue);
+ } else {
+ // Otherwise, keep the checkcast to preserve verification errors. E.g., down-cast:
+ // A < B < C
+ // c = ... // Even though we know c is of type A,
+ // a' = (B) c; // (this could be removed, since chained below.)
+ // a'' = (A) a'; // this should remain for runtime verification.
+ assert !inTypeLattice.isNull();
+ assert outTypeLattice.asNullable().equals(castTypeLattice.asNullable());
}
- // Otherwise, keep the checkcast to preserve verification errors. E.g., down-cast:
- // A < B < C
- // c = ... // Even though we know c is of type A,
- // a' = (B) c; // (this could be removed, since chained below.)
- // a'' = (A) a'; // this should remain for runtime verification.
- assert outTypeLattice.equals(castTypeLattice);
}
}
// ... v1
@@ -1689,16 +1695,20 @@
if (needToRemoveTrivialPhis) {
code.removeAllTrivialPhis();
}
- it = code.instructionIterator();
assert code.isConsistentSSA();
}
private void removeOrReplaceByDebugLocalWrite(
- InstructionIterator it, Value inValue, Value outValue) {
- if (outValue.getLocalInfo() != inValue.getLocalInfo() && outValue.hasLocalInfo()) {
+ Instruction currentInstruction, InstructionIterator it, Value inValue, Value outValue) {
+ if (outValue.hasLocalInfo() && outValue.getLocalInfo() != inValue.getLocalInfo()) {
DebugLocalWrite debugLocalWrite = new DebugLocalWrite(outValue, inValue);
it.replaceCurrentInstruction(debugLocalWrite);
} else {
+ if (outValue.hasLocalInfo()) {
+ assert outValue.getLocalInfo() == inValue.getLocalInfo();
+ // Should remove the end-marker before replacing the current instruction.
+ currentInstruction.removeDebugValue(outValue.getLocalInfo());
+ }
outValue.replaceUsers(inValue);
it.removeOrReplaceByDebugLocalRead();
}
@@ -2153,7 +2163,8 @@
for (ConstInstruction value : values) {
stringValues.add(value.outValue());
}
- Value invokeValue = code.createValue(newArray.outType(), newArray.getLocalInfo());
+ Value invokeValue = code.createValue(
+ newArray.outValue().getTypeLattice(), newArray.getLocalInfo());
InvokeNewArray invoke =
new InvokeNewArray(dexItemFactory.stringArrayType, invokeValue, stringValues);
for (Value value : newArray.inValues()) {
@@ -2662,7 +2673,7 @@
InstructionListIterator throwNullInsnIterator = throwNullBlock.listIterator();
// Insert 'null' constant.
- Value nullValue = code.createValue(ValueType.OBJECT, gotoInsn.getLocalInfo());
+ Value nullValue = code.createValue(TypeLatticeElement.NULL, gotoInsn.getLocalInfo());
ConstNumber nullConstant = new ConstNumber(nullValue, 0);
nullConstant.setPosition(insn.getPosition());
throwNullInsnIterator.add(nullConstant);
@@ -2744,7 +2755,7 @@
(theIf.getType() == Type.EQ &&
trueNumber.isIntegerOne() &&
falseNumber.isIntegerZero())) {
- Value newOutValue = code.createValue(phi.outType(), phi.getLocalInfo());
+ Value newOutValue = code.createValue(phi.getTypeLattice(), phi.getLocalInfo());
ConstNumber cstToUse = trueNumber.isIntegerOne() ? trueNumber : falseNumber;
BasicBlock phiBlock = phi.getBlock();
Position phiPosition = phiBlock.getPosition();
@@ -2971,7 +2982,8 @@
}
private Value addConstString(IRCode code, InstructionListIterator iterator, String s) {
- Value value = code.createValue(ValueType.OBJECT);
+ TypeLatticeElement typeLattice = TypeLatticeElement.stringClassType(appInfo);
+ Value value = code.createValue(typeLattice);
iterator.add(new ConstString(value, dexItemFactory.createString(s)));
return value;
}
@@ -2998,9 +3010,10 @@
// Now that the block is split there should not be any catch handlers in the block.
assert !block.hasCatchHandlers();
- Value out = code.createValue(ValueType.OBJECT);
DexType javaLangSystemType = dexItemFactory.createType("Ljava/lang/System;");
DexType javaIoPrintStreamType = dexItemFactory.createType("Ljava/io/PrintStream;");
+ Value out = code.createValue(
+ TypeLatticeElement.fromDexType(javaIoPrintStreamType, appInfo, false));
DexProto proto = dexItemFactory.createProto(dexItemFactory.voidType, dexItemFactory.objectType);
DexMethod print = dexItemFactory.createMethod(javaIoPrintStreamType, proto, "print");
@@ -3010,11 +3023,11 @@
new StaticGet(MemberType.OBJECT, out,
dexItemFactory.createField(javaLangSystemType, javaIoPrintStreamType, "out")));
- Value value = code.createValue(ValueType.OBJECT);
+ Value value = code.createValue(TypeLatticeElement.stringClassType(appInfo));
iterator.add(new ConstString(value, dexItemFactory.createString("INVOKE ")));
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
- value = code.createValue(ValueType.OBJECT);
+ value = code.createValue(TypeLatticeElement.stringClassType(appInfo));
iterator.add(
new ConstString(value, dexItemFactory.createString(method.method.qualifiedName())));
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
@@ -3040,7 +3053,7 @@
eol.link(successor);
Value argument = arguments.get(i);
- if (argument.outType() != ValueType.OBJECT) {
+ if (!argument.getTypeLattice().isReference()) {
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, primitive)));
} else {
// Insert "if (argument != null) ...".
@@ -3068,7 +3081,7 @@
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, nul)));
iterator = isNotNullBlock.listIterator();
iterator.setInsertionPosition(position);
- value = code.createValue(ValueType.OBJECT);
+ value = code.createValue(TypeLatticeElement.classClassType(appInfo));
iterator.add(new InvokeVirtual(dexItemFactory.objectMethods.getClass, value,
ImmutableList.of(arguments.get(i))));
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index 9f57e52..37cfb44 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -110,12 +110,12 @@
Value receiver = invoke.getReceiver();
TypeLatticeElement receiverTypeLattice = receiver.getTypeLattice();
TypeLatticeElement castTypeLattice =
- TypeLatticeElement.fromDexType(appInfo, holderType, receiverTypeLattice.isNullable());
+ TypeLatticeElement.fromDexType(holderType, appInfo, receiverTypeLattice.isNullable());
// Avoid adding trivial cast and up-cast.
// We should not use strictlyLessThan(castType, receiverType), which detects downcast,
// due to side-casts, e.g., A (unused) < I, B < I, and cast from A to B.
- // TODO(b/72693244): Soon, there won't be a value with Bottom at this point.
- if (receiverTypeLattice.isBottom()
+ // TODO(b/72693244): Soon, there won't be a value with imprecise type at this point.
+ if (!receiverTypeLattice.isPreciseType()
|| !TypeLatticeElement.lessThanOrEqual(
appInfo, receiverTypeLattice, castTypeLattice)) {
Value newReceiver = null;
@@ -140,8 +140,8 @@
if (newReceiver == null) {
newReceiver =
receiver.definition != null
- ? code.createValue(receiver.outType(), receiver.definition.getLocalInfo())
- : code.createValue(receiver.outType());
+ ? code.createValue(receiverTypeLattice, receiver.definition.getLocalInfo())
+ : code.createValue(receiverTypeLattice);
// Cache the new receiver with a narrower type to avoid redundant checkcast.
castedReceiverCache.putIfAbsent(receiver, new IdentityHashMap<>());
castedReceiverCache.get(receiver).put(holderType, newReceiver);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 1a23da1..98de5be 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstancePut;
@@ -22,7 +23,6 @@
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.StaticPut;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ProguardMemberRule;
import java.util.function.Predicate;
@@ -68,19 +68,19 @@
ProguardMemberRule rule, IRCode code, Instruction instruction) {
// Check if this value can be assumed constant.
Instruction replacement = null;
- ValueType valueType = instruction.outValue().outType();
+ TypeLatticeElement typeLattice = instruction.outValue().getTypeLattice();
if (rule != null && rule.hasReturnValue() && rule.getReturnValue().isSingleValue()) {
- Value value = code.createValue(valueType, instruction.getLocalInfo());
- assert valueType != ValueType.OBJECT || rule.getReturnValue().isNull();
+ Value value = code.createValue(typeLattice, instruction.getLocalInfo());
+ assert !typeLattice.isReference() || rule.getReturnValue().isNull();
replacement = new ConstNumber(value, rule.getReturnValue().getSingleValue());
}
if (replacement == null &&
rule != null && rule.hasReturnValue() && rule.getReturnValue().isField()) {
DexField field = rule.getReturnValue().getField();
- assert ValueType.fromDexType(field.type) == valueType;
+ assert TypeLatticeElement.fromDexType(field.type) == typeLattice;
DexEncodedField staticField = appInfo.lookupStaticTarget(field.clazz, field);
if (staticField != null) {
- Value value = code.createValue(valueType, instruction.getLocalInfo());
+ Value value = code.createValue(typeLattice, instruction.getLocalInfo());
replacement = staticField.getStaticValue().asConstInstruction(false, value);
} else {
throw new CompilationError(field.clazz.toSourceString() + "." + field.name.toString() +
@@ -164,8 +164,8 @@
}
if (target.getOptimizationInfo().returnsConstant()) {
long constant = target.getOptimizationInfo().getReturnedConstant();
- ValueType valueType = invoke.outType();
- Value value = code.createValue(valueType, invoke.getLocalInfo());
+ Value value = code.createValue(
+ invoke.outValue().getTypeLattice(), invoke.getLocalInfo());
Instruction knownConstReturn = new ConstNumber(value, constant);
invoke.outValue().replaceUsers(value);
invoke.setOutValue(null);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index 536eac8..eed1c47 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.ir.code.NonNull;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -119,9 +118,9 @@
// ...
// A: non_null_rcv <- non-null(rcv)
// ...y
- // TODO(b/72693244): Attach lattice when Value is created.
- Value nonNullValue =
- code.createValue(ValueType.OBJECT, knownToBeNonNullValue.getLocalInfo());
+ Value nonNullValue = code.createValue(
+ knownToBeNonNullValue.getTypeLattice(),
+ knownToBeNonNullValue.getLocalInfo());
nonNullValueCollector.add(nonNullValue);
NonNull nonNull = new NonNull(nonNullValue, knownToBeNonNullValue, current);
nonNull.setPosition(current.getPosition());
@@ -219,9 +218,9 @@
}
// Avoid adding a non-null for the value without meaningful users.
if (!dominatedUsers.isEmpty() || !dominatedPhiUsersWithPositions.isEmpty()) {
- // TODO(b/72693244): Attach lattice when Value is created.
Value nonNullValue = code.createValue(
- knownToBeNonNullValue.outType(), knownToBeNonNullValue.getLocalInfo());
+ knownToBeNonNullValue.getTypeLattice(),
+ knownToBeNonNullValue.getLocalInfo());
nonNullValueCollector.add(nonNullValue);
NonNull nonNull = new NonNull(nonNullValue, knownToBeNonNullValue, theIf);
InstructionListIterator targetIterator = target.listIterator();
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 e02222f..708dc12 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
@@ -24,6 +24,7 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Add;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
@@ -1031,8 +1032,8 @@
public void buildPrelude(IRBuilder builder) {
// Fill in the Argument instructions in the argument block.
for (int i = 0; i < outline.arguments.size(); i++) {
- ValueType valueType = outline.arguments.get(i).outType();
- builder.addNonThisArgument(i, valueType);
+ TypeLatticeElement typeLattice = outline.arguments.get(i).getTypeLattice();
+ builder.addNonThisArgument(i, typeLattice);
}
}
@@ -1076,8 +1077,8 @@
Value outValue = null;
if (template.outValue() != null) {
Value value = template.outValue();
- outValue = builder
- .writeRegister(outline.argumentCount(), value.outType(), ThrowingInfo.CAN_THROW);
+ outValue = builder.writeRegister(
+ outline.argumentCount(), value.getTypeLattice(), ThrowingInfo.CAN_THROW);
}
Instruction newInstruction = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 0ef4597..6999f9a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -137,6 +137,7 @@
// of roots to avoid infinite inlining. Looping makes possible for some roots to
// become eligible after other roots are inlined.
+ boolean anyInlinedMethods = false;
boolean repeat;
do {
repeat = false;
@@ -169,18 +170,24 @@
}
// Inline the class instance.
- boolean anyInlinedMethods = processor.processInlining(code, inliner);
+ anyInlinedMethods |= processor.processInlining(code, inliner);
// Restore normality.
code.removeAllTrivialPhis();
assert code.isConsistentSSA();
- if (anyInlinedMethods) {
- codeRewriter.simplifyIf(code);
- }
rootsIterator.remove();
repeat = true;
}
} while (repeat);
+
+ if (anyInlinedMethods) {
+ // If a method was inlined we may be able to remove check-cast instructions because we may
+ // have more information about the types of the arguments at the call site. This is
+ // particularly important for bridge methods.
+ codeRewriter.removeCasts(code);
+ // If a method was inlined we may be able to prune additional branches.
+ codeRewriter.simplifyIf(code);
+ }
}
private boolean isClassEligible(AppInfo appInfo, DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java
index 714c28b..8ed50ce 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
@@ -13,7 +14,6 @@
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Phi.RegisterReadType;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.LinkedList;
@@ -89,7 +89,7 @@
new Phi(
code.valueNumberGenerator.next(),
block,
- ValueType.fromDexType(field.type),
+ TypeLatticeElement.fromDexType(field.type),
null,
RegisterReadType.NORMAL);
ins.put(block, phi);
@@ -137,7 +137,7 @@
assert root == valueProducingInsn;
if (defaultValue == null) {
// If we met newInstance it means that default value is supposed to be used.
- defaultValue = code.createValue(ValueType.fromDexType(field.type));
+ defaultValue = code.createValue(TypeLatticeElement.fromDexType(field.type));
ConstNumber defaultValueInsn = new ConstNumber(defaultValue, 0);
defaultValueInsn.setPosition(root.getPosition());
LinkedList<Instruction> instructions = block.getInstructions();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
index eb7826e..030cd4f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.lambda;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
@@ -139,6 +140,7 @@
}
};
+ public final AppInfo appInfo;
public final DexItemFactory factory;
public final Kotlin kotlin;
@@ -156,13 +158,15 @@
public final ListIterator<BasicBlock> blocks;
private InstructionListIterator instructions;
- CodeProcessor(DexItemFactory factory,
+ CodeProcessor(
+ AppInfo appInfo,
Function<DexType, Strategy> strategyProvider,
LambdaTypeVisitor lambdaChecker,
DexEncodedMethod method, IRCode code) {
+ this.appInfo = appInfo;
this.strategyProvider = strategyProvider;
- this.factory = factory;
+ this.factory = appInfo.dexItemFactory;
this.kotlin = factory.kotlin;
this.lambdaChecker = lambdaChecker;
this.method = method;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index d1b56f2..270f8ba 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
@@ -98,6 +99,7 @@
// should not be happening very frequently and we ignore possible overhead.
private final Set<DexEncodedMethod> methodsToReprocess = Sets.newIdentityHashSet();
+ private final AppInfo appInfo;
private final DexItemFactory factory;
private final Kotlin kotlin;
private final DiagnosticsHandler reporter;
@@ -109,8 +111,9 @@
// Lambda visitor throwing Unreachable on each lambdas it sees.
private final LambdaTypeVisitor lambdaChecker;
- public LambdaMerger(DexItemFactory factory, DiagnosticsHandler reporter) {
- this.factory = factory;
+ public LambdaMerger(AppInfo appInfo, DiagnosticsHandler reporter) {
+ this.appInfo = appInfo;
+ this.factory = appInfo.dexItemFactory;
this.kotlin = factory.kotlin;
this.reporter = reporter;
@@ -346,7 +349,7 @@
private final class AnalysisStrategy extends CodeProcessor {
private AnalysisStrategy(DexEncodedMethod method, IRCode code) {
- super(LambdaMerger.this.factory,
+ super(LambdaMerger.this.appInfo,
LambdaMerger.this::strategyProvider, lambdaInvalidator, method, code);
}
@@ -383,7 +386,7 @@
private final class ApplyStrategy extends CodeProcessor {
private ApplyStrategy(DexEncodedMethod method, IRCode code) {
- super(LambdaMerger.this.factory,
+ super(LambdaMerger.this.appInfo,
LambdaMerger.this::strategyProvider, lambdaChecker, method, code);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
index 19d6bda..5177e4a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
@@ -45,7 +46,7 @@
if (group.isSingletonLambda(lambda)) {
int id = group.lambdaId(lambda);
add(builder -> builder.addNewInstance(instance, groupClassType));
- add(builder -> builder.addConst(ValueType.INT, lambdaId, id));
+ add(builder -> builder.addConst(TypeLatticeElement.INT, lambdaId, id));
add(builder -> builder.addInvoke(Type.DIRECT,
lambdaConstructorMethod, lambdaConstructorMethod.proto, argTypes, argRegisters));
add(builder -> builder.addStaticPut(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
index 76bf797..f677b46 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
@@ -231,7 +232,7 @@
@Override
void prepareSuperConstructorCall(int receiverRegister) {
int arityRegister = nextRegister(ValueType.INT);
- add(builder -> builder.addConst(ValueType.INT, arityRegister, arity));
+ add(builder -> builder.addConst(TypeLatticeElement.INT, arityRegister, arity));
add(builder -> builder.addInvoke(Type.DIRECT, lambdaInitializer, lambdaInitializer.proto,
Lists.newArrayList(ValueType.OBJECT, ValueType.INT),
Lists.newArrayList(receiverRegister, arityRegister)));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
index e265756..538d7be 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.InstanceGet;
@@ -22,7 +23,6 @@
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.StaticPut;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
import com.android.tools.r8.ir.optimize.lambda.CodeProcessor;
import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
@@ -113,7 +113,9 @@
@Override
public void patch(CodeProcessor context, NewInstance newInstance) {
NewInstance patchedNewInstance = new NewInstance(
- group.getGroupClassType(), context.code.createValue(ValueType.OBJECT));
+ group.getGroupClassType(),
+ context.code.createValue(
+ TypeLatticeElement.fromDexType(newInstance.clazz, context.appInfo, false)));
context.instructions().replaceCurrentInstruction(patchedNewInstance);
}
@@ -157,7 +159,9 @@
// Since all captured values of non-primitive types are stored in fields of type
// java.lang.Object, we need to cast them to appropriate type to satisfy the verifier.
- Value newValue = context.code.createValue(ValueType.OBJECT, newInstanceGet.getLocalInfo());
+ TypeLatticeElement castTypeLattice =
+ TypeLatticeElement.fromDexType(fieldType, context.appInfo, false);
+ Value newValue = context.code.createValue(castTypeLattice, newInstanceGet.getLocalInfo());
newInstanceGet.outValue().replaceUsers(newValue);
CheckCast cast = new CheckCast(newValue, newInstanceGet.outValue(), fieldType);
cast.setPosition(newInstanceGet.getPosition());
@@ -180,7 +184,10 @@
@Override
public void patch(CodeProcessor context, StaticGet staticGet) {
context.instructions().replaceCurrentInstruction(
- new StaticGet(staticGet.getType(), context.code.createValue(ValueType.OBJECT),
+ new StaticGet(
+ staticGet.getType(),
+ context.code.createValue(
+ TypeLatticeElement.fromDexType(staticGet.getField().type, context.appInfo, true)),
mapSingletonInstanceField(context.factory, staticGet.getField())));
}
@@ -195,7 +202,7 @@
DexType lambda = method.holder;
// Create constant with lambda id.
- Value lambdaIdValue = context.code.createValue(ValueType.INT);
+ Value lambdaIdValue = context.code.createValue(TypeLatticeElement.INT);
ConstNumber lambdaId = new ConstNumber(lambdaIdValue, group.lambdaId(lambda));
lambdaId.setPosition(invoke.getPosition());
context.instructions().previous();
@@ -214,7 +221,8 @@
private Value createValueForType(CodeProcessor context, DexType returnType) {
return returnType == context.factory.voidType ? null :
- context.code.createValue(ValueType.fromDexType(returnType));
+ context.code.createValue(
+ TypeLatticeElement.fromDexType(returnType, context.appInfo, true));
}
private List<Value> mapInitializerArgs(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 916679d..669baf9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
@@ -23,7 +24,6 @@
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.StaticPut;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CallSiteInformation;
import com.android.tools.r8.ir.conversion.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.Outliner;
@@ -244,7 +244,7 @@
Value newValue = null;
Value outValue = invoke.outValue();
if (outValue != null) {
- newValue = code.createValue(outValue.outType());
+ newValue = code.createValue(outValue.getTypeLattice());
DebugLocalInfo localInfo = outValue.getLocalInfo();
if (localInfo != null) {
newValue.setLocalInfo(localInfo);
@@ -272,7 +272,9 @@
it.replaceCurrentInstruction(
new StaticGet(
MemberType.fromDexType(field.type),
- code.createValue(ValueType.fromDexType(field.type), outValue.getLocalInfo()),
+ code.createValue(
+ TypeLatticeElement.fromDexType(field.type, classStaticizer.appInfo, true),
+ outValue.getLocalInfo()),
field
)
);
@@ -300,7 +302,8 @@
Value outValue = invoke.outValue();
Value newOutValue = method.proto.returnType.isVoidType() ? null
: code.createValue(
- ValueType.fromDexType(method.proto.returnType),
+ TypeLatticeElement.fromDexType(
+ method.proto.returnType, classStaticizer.appInfo, true),
outValue == null ? null : outValue.getLocalInfo());
it.replaceCurrentInstruction(
new InvokeStatic(newMethod, newOutValue, invoke.inValues()));
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 b4995c9..9345bb9 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
@@ -10,6 +10,7 @@
import com.android.tools.r8.cf.FixedLocalValue;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Add;
import com.android.tools.r8.ir.code.And;
import com.android.tools.r8.ir.code.ArithmeticBinop;
@@ -27,7 +28,6 @@
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Sub;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.code.Xor;
import com.android.tools.r8.ir.regalloc.RegisterPositions.Type;
import com.android.tools.r8.logging.Log;
@@ -2673,8 +2673,8 @@
return true;
}
- private Value createValue(ValueType type) {
- Value value = code.createValue(type, null);
+ private Value createValue(TypeLatticeElement typeLattice) {
+ Value value = code.createValue(typeLattice, null);
value.setNeedsRegister(true);
return value;
}
@@ -2726,7 +2726,7 @@
argument.isLinked() ||
argument == previous ||
argument.hasRegisterConstraint()) {
- newArgument = createValue(argument.outType());
+ newArgument = createValue(argument.getTypeLattice());
Move move = new Move(newArgument, argument);
move.setBlock(invoke.getBlock());
replaceArgument(invoke, i, newArgument);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
index 031d161..daa1e30 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
@@ -139,22 +139,25 @@
if (move.definition.isArgument()) {
Argument argument = move.definition.asArgument();
int argumentRegister = argument.outValue().getLiveIntervals().getRegister();
- Value to = new FixedRegisterValue(argument.outType(), move.dst);
- Value from = new FixedRegisterValue(argument.outType(), argumentRegister);
+ Value to =
+ new FixedRegisterValue(argument.outValue().getTypeLattice(), move.dst);
+ Value from =
+ new FixedRegisterValue(argument.outValue().getTypeLattice(), argumentRegister);
instruction = new Move(to, from);
} else {
assert move.definition.isOutConstant();
ConstInstruction definition = move.definition.getOutConstantConstInstruction();
if (definition.isConstNumber()) {
- Value to = new FixedRegisterValue(move.definition.outType(), move.dst);
+ Value to =
+ new FixedRegisterValue(move.definition.outValue().getTypeLattice(), move.dst);
instruction = new ConstNumber(to, definition.asConstNumber().getRawValue());
} else {
throw new Unreachable("Unexpected definition");
}
}
} else {
- Value to = new FixedRegisterValue(move.type.toValueType(), move.dst);
- Value from = new FixedRegisterValue(move.type.toValueType(), valueMap.get(move.src));
+ Value to = new FixedRegisterValue(move.type.toTypeLattice(), move.dst);
+ Value from = new FixedRegisterValue(move.type.toTypeLattice(), valueMap.get(move.src));
instruction = new Move(to, from);
}
instruction.setPosition(position);
@@ -176,9 +179,9 @@
// (taking the value map into account). If not, we can reuse the temp register instead
// of generating a new one.
Value to = new FixedRegisterValue(
- moveWithSrc.type.toValueType(), tempRegister + usedTempRegisters);
+ moveWithSrc.type.toTypeLattice(), tempRegister + usedTempRegisters);
Value from = new FixedRegisterValue(
- moveWithSrc.type.toValueType(), valueMap.get(moveWithSrc.src));
+ moveWithSrc.type.toTypeLattice(), valueMap.get(moveWithSrc.src));
Move instruction = new Move(to, from);
instruction.setPosition(position);
insertAt.add(instruction);
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
index cd9824f..164e083 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Position;
@@ -177,7 +178,8 @@
@Override
public final void buildPrelude(IRBuilder builder) {
if (receiver != null) {
- receiverValue = builder.writeRegister(receiverRegister, ValueType.OBJECT, NO_THROW);
+ receiverValue = builder.writeRegister(
+ receiverRegister, TypeLatticeElement.fromDexType(receiver), NO_THROW);
builder.add(new Argument(receiverValue));
receiverValue.markAsThis();
}
@@ -185,8 +187,8 @@
// Fill in the Argument instructions in the argument block.
DexType[] parameters = proto.parameters.values;
for (int i = 0; i < parameters.length; i++) {
- ValueType valueType = ValueType.fromDexType(parameters[i]);
- Value paramValue = builder.writeRegister(paramRegisters[i], valueType, NO_THROW);
+ TypeLatticeElement typeLattice = TypeLatticeElement.fromDexType(parameters[i]);
+ Value paramValue = builder.writeRegister(paramRegisters[i], typeLattice, NO_THROW);
paramValues[i] = paramValue;
builder.add(new Argument(paramValue));
}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 37e6de9..051b81f 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -42,6 +42,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -188,8 +189,11 @@
}
}
- private void parseError(DexDefinition item, Origin origin, GenericSignatureFormatError e) {
- StringBuilder message = new StringBuilder("Invalid signature for ");
+ private void parseError(
+ DexDefinition item, Origin origin, String signature, GenericSignatureFormatError e) {
+ StringBuilder message = new StringBuilder("Invalid signature '");
+ message.append(signature);
+ message.append("' for ");
if (item.isDexClass()) {
message.append("class ");
message.append((item.asDexClass()).getType().toSourceString());
@@ -202,43 +206,54 @@
message.append(item.toSourceString());
}
message.append(".\n");
+ message.append("Signature is ignored and will not be present in the output.\n");
+ message.append("Parser error: ");
message.append(e.getMessage());
reporter.warning(new StringDiagnostic(message.toString(), origin));
}
private void renameTypesInGenericSignatures() {
for (DexClass clazz : appInfo.classes()) {
- clazz.annotations = rewriteGenericSignatures(clazz.annotations,
- genericSignatureParser::parseClassSignature,
- e -> parseError(clazz, clazz.getOrigin(), e));
- clazz.forEachField(field ->
- field.annotations = rewriteGenericSignatures(
- field.annotations, genericSignatureParser::parseFieldSignature,
- e -> parseError(field, clazz.getOrigin(), e)));
- clazz.forEachMethod(method ->
- method.annotations = rewriteGenericSignatures(
- method.annotations, genericSignatureParser::parseMethodSignature,
- e -> parseError(method, clazz.getOrigin(), e)));
+ clazz.annotations =
+ rewriteGenericSignatures(
+ clazz.annotations,
+ genericSignatureParser::parseClassSignature,
+ (signature, e) -> parseError(clazz, clazz.getOrigin(), signature, e));
+ clazz.forEachField(
+ field ->
+ field.annotations =
+ rewriteGenericSignatures(
+ field.annotations,
+ genericSignatureParser::parseFieldSignature,
+ (signature, e) -> parseError(field, clazz.getOrigin(), signature, e)));
+ clazz.forEachMethod(
+ method ->
+ method.annotations =
+ rewriteGenericSignatures(
+ method.annotations,
+ genericSignatureParser::parseMethodSignature,
+ (signature, e) -> parseError(method, clazz.getOrigin(), signature, e)));
}
}
private DexAnnotationSet rewriteGenericSignatures(
DexAnnotationSet annotations,
Consumer<String> parser,
- Consumer<GenericSignatureFormatError> parseError) {
+ BiConsumer<String, GenericSignatureFormatError> parseError) {
// There can be no more than one signature annotation in an annotation set.
final int VALID = -1;
int invalid = VALID;
for (int i = 0; i < annotations.annotations.length && invalid == VALID; i++) {
DexAnnotation annotation = annotations.annotations[i];
if (DexAnnotation.isSignatureAnnotation(annotation, appInfo.dexItemFactory)) {
+ String signature = DexAnnotation.getSignature(annotation);
try {
- parser.accept(DexAnnotation.getSignature(annotation));
+ parser.accept(signature);
annotations.annotations[i] = DexAnnotation.createSignatureAnnotation(
genericSignatureRewriter.getRenamedSignature(),
appInfo.dexItemFactory);
} catch (GenericSignatureFormatError e) {
- parseError.accept(e);
+ parseError.accept(signature, e);
invalid = i;
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
index 8f9e2f5..59e0782 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -130,7 +130,7 @@
assert iterator.peekPrevious() == fieldPut;
iterator.previous();
// Prepare $decoupled just before $fieldPut
- Value newIn = code.createValue(in.outType(), in.getLocalInfo());
+ Value newIn = code.createValue(in.getTypeLattice(), in.getLocalInfo());
ConstString decoupled = new ConstString(newIn, itemBasedString);
decoupled.setPosition(fieldPut.getPosition());
// If the current block has catch handler, split into two blocks.
@@ -192,7 +192,7 @@
assert iterator.peekPrevious() == invoke;
iterator.previous();
// Prepare $decoupled just before $invoke
- Value newIn = code.createValue(in.outType(), in.getLocalInfo());
+ Value newIn = code.createValue(in.getTypeLattice(), in.getLocalInfo());
ConstString decoupled = new ConstString(newIn, itemBasedString);
decoupled.setPosition(invoke.getPosition());
changes[positionOfIdentifier] = newIn;
@@ -239,7 +239,7 @@
assert iterator.peekPrevious() == invoke;
iterator.previous();
// Prepare $decoupled just before $invoke
- Value newIn = code.createValue(in.outType(), in.getLocalInfo());
+ Value newIn = code.createValue(in.getTypeLattice(), in.getLocalInfo());
ConstString decoupled = new ConstString(newIn, itemBasedString);
decoupled.setPosition(invoke.getPosition());
changes[i] = newIn;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 9145de1..de42c18 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo.ResolutionResult;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.Descriptor;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexApplication;
@@ -95,7 +96,7 @@
private boolean tracingMainDex = false;
private final AppInfoWithSubtyping appInfo;
- private final GraphLense graphLense;
+ private final AppView<? extends AppInfoWithSubtyping> appView;
private final InternalOptions options;
private RootSet rootSet;
@@ -220,25 +221,34 @@
*/
private final ProguardConfiguration.Builder compatibility;
- public Enqueuer(
- AppInfoWithSubtyping appInfo,
- GraphLense graphLense,
- InternalOptions options,
- boolean forceProguardCompatibility) {
- this(appInfo, graphLense, options, forceProguardCompatibility, null);
+ public Enqueuer(AppView<? extends AppInfoWithSubtyping> appView, InternalOptions options) {
+ this(appView, options, options.forceProguardCompatibility, null);
}
public Enqueuer(
- AppInfoWithSubtyping appInfo,
- GraphLense graphLense,
+ AppView<? extends AppInfoWithSubtyping> appView,
+ InternalOptions options,
+ ProguardConfiguration.Builder compatibility) {
+ this(appView, options, options.forceProguardCompatibility, compatibility);
+ }
+
+ public Enqueuer(
+ AppView<? extends AppInfoWithSubtyping> appView,
+ InternalOptions options,
+ boolean forceProguardCompatibility) {
+ this(appView, options, forceProguardCompatibility, null);
+ }
+
+ public Enqueuer(
+ AppView<? extends AppInfoWithSubtyping> appView,
InternalOptions options,
boolean forceProguardCompatibility,
ProguardConfiguration.Builder compatibility) {
- this.appInfo = appInfo;
- this.graphLense = graphLense;
+ this.appInfo = appView.appInfo();
+ this.appView = appView;
this.compatibility = compatibility;
- this.options = options;
this.forceProguardCompatibility = forceProguardCompatibility;
+ this.options = options;
}
private void enqueueRootItems(Map<DexDefinition, ProguardKeepRule> items) {
@@ -255,13 +265,18 @@
if (item.isDexClass()) {
DexClass clazz = item.asDexClass();
workList.add(Action.markInstantiated(clazz, reason));
- if (forceProguardCompatibility && clazz.hasDefaultInitializer()) {
- ProguardKeepRule compatRule =
+ if (clazz.hasDefaultInitializer()) {
+ if (forceProguardCompatibility) {
+ ProguardKeepRule compatRule =
ProguardConfigurationUtils.buildDefaultInitializerKeepRule(clazz);
- proguardCompatibilityWorkList.add(
- Action.markMethodLive(
- clazz.getDefaultInitializer(),
- KeepReason.dueToProguardCompatibilityKeepRule(compatRule)));
+ proguardCompatibilityWorkList.add(
+ Action.markMethodLive(
+ clazz.getDefaultInitializer(),
+ KeepReason.dueToProguardCompatibilityKeepRule(compatRule)));
+ }
+ if (clazz.isExternalizable(appInfo)) {
+ workList.add(Action.markMethodLive(clazz.getDefaultInitializer(), reason));
+ }
}
} else if (item.isDexEncodedField()) {
workList.add(Action.markFieldKept(item.asDexEncodedField(), reason));
@@ -1272,7 +1287,7 @@
numOfLiveItemsAfterProcessing += (long) liveFields.items.size();
if (numOfLiveItemsAfterProcessing > numOfLiveItems) {
RootSetBuilder consequentSetBuilder =
- new RootSetBuilder(appInfo, rootSet.ifRules, options);
+ new RootSetBuilder(appView, rootSet.ifRules, options);
ConsequentRootSet consequentRootSet = consequentSetBuilder.runForIfRules(
executorService, liveTypes, liveMethods.getItems(), liveFields.getItems());
enqueueRootItems(consequentRootSet.noShrinking);
@@ -1518,7 +1533,7 @@
private void handleReflectiveBehavior(DexEncodedMethod method) {
DexType originHolder = method.method.holder;
Origin origin = appInfo.originFor(originHolder);
- IRCode code = method.buildIR(appInfo, graphLense, options, origin);
+ IRCode code = method.buildIR(appInfo, appView.graphLense(), options, origin);
code.instructionIterator().forEachRemaining(this::handleReflectiveBehavior);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
index 5d610a8..2aff5df 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
@@ -320,11 +320,12 @@
}
protected StringBuilder append(StringBuilder builder, boolean includeMemberRules) {
- StringUtils.appendNonEmpty(builder, "@", classAnnotation, null);
- StringUtils.appendNonEmpty(builder, "", classAccessFlags, null);
- StringUtils.appendNonEmpty(builder, "!", negatedClassAccessFlags.toString().replace(" ", " !"),
- null);
- if (builder.length() > 0) {
+ boolean needsSpaceBeforeClassType =
+ StringUtils.appendNonEmpty(builder, "@", classAnnotation, null)
+ | StringUtils.appendNonEmpty(builder, "", classAccessFlags, null)
+ | StringUtils.appendNonEmpty(
+ builder, "!", negatedClassAccessFlags.toString().replace(" ", " !"), null);
+ if (needsSpaceBeforeClassType) {
builder.append(' ');
}
if (classTypeNegated) {
@@ -339,12 +340,12 @@
builder.append(' ');
builder.append(inheritanceClassName);
}
- if (includeMemberRules) {
- builder.append(" {\n");
+ if (includeMemberRules && !memberRules.isEmpty()) {
+ builder.append(" {").append(System.lineSeparator());
memberRules.forEach(memberRule -> {
builder.append(" ");
builder.append(memberRule);
- builder.append(";\n");
+ builder.append(";").append(System.lineSeparator());
});
builder.append("}");
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java
index fe31b14..49f99dc 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepAttributes.java
@@ -16,6 +16,9 @@
public static final String ENCLOSING_METHOD = "EnclosingMethod";
public static final String SIGNATURE = "Signature";
public static final String EXCEPTIONS = "Exceptions";
+ public static final String LINE_NUMBER_TABLE = "LineNumberTable";
+ public static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
+ public static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
public static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
public static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
public static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
@@ -36,6 +39,9 @@
public boolean enclosingMethod = false;
public boolean signature = false;
public boolean exceptions = false;
+ public boolean lineNumberTable = false;
+ public boolean localVariableTable = false;
+ public boolean localVariableTypeTable = false;
public boolean sourceDebugExtension = false;
public boolean runtimeVisibleAnnotations = false;
public boolean runtimeInvisibleAnnotations = false;
@@ -108,6 +114,9 @@
innerClasses = update(innerClasses, INNER_CLASSES, patterns);
enclosingMethod = update(enclosingMethod, ENCLOSING_METHOD, patterns);
signature = update(signature, SIGNATURE, patterns);
+ lineNumberTable = update(lineNumberTable, LINE_NUMBER_TABLE, patterns);
+ localVariableTable = update(localVariableTable, LOCAL_VARIABLE_TABLE, patterns);
+ localVariableTypeTable = update(localVariableTypeTable, LOCAL_VARIABLE_TYPE_TABLE, patterns);
exceptions = update(exceptions, EXCEPTIONS, patterns);
sourceDebugExtension = update(sourceDebugExtension, SOURCE_DEBUG_EXTENSION, patterns);
runtimeVisibleAnnotations = update(runtimeVisibleAnnotations, RUNTIME_VISIBLE_ANNOTATIONS,
@@ -146,6 +155,18 @@
throw new CompilationError("Attribute Signature requires InnerClasses attribute. Check "
+ "-keepattributes directive.");
}
+ if (forceProguardCompatibility && localVariableTable && !lineNumberTable) {
+ // If locals are kept, assume line numbers should be kept too.
+ lineNumberTable = true;
+ compatibility.addKeepAttributePatterns(
+ ImmutableList.of(ProguardKeepAttributes.LINE_NUMBER_TABLE));
+ }
+ if (localVariableTable && !lineNumberTable) {
+ throw new CompilationError(
+ "Attribute " + LOCAL_VARIABLE_TABLE
+ + " requires " + LINE_NUMBER_TABLE
+ + ". Check -keepattributes directive.");
+ }
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 30def9e..e6f6a17 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
@@ -51,7 +52,7 @@
public class RootSetBuilder {
- private final AppInfo appInfo;
+ private final AppView<? extends AppInfo> appView;
private final DirectMappedDexApplication application;
private final Collection<ProguardConfigurationRule> rules;
private final Map<DexDefinition, ProguardKeepRule> noShrinking = new IdentityHashMap<>();
@@ -76,22 +77,20 @@
private final Set<ProguardIfRule> ifRules = Sets.newIdentityHashSet();
public RootSetBuilder(
- AppInfo appInfo,
+ AppView<? extends AppInfo> appView,
DexApplication application,
List<ProguardConfigurationRule> rules,
InternalOptions options) {
- this.appInfo = appInfo;
+ this.appView = appView;
this.application = application.asDirect();
this.rules = rules == null ? null : Collections.unmodifiableCollection(rules);
this.options = options;
}
RootSetBuilder(
- AppInfo appInfo,
- Set<ProguardIfRule> ifRules,
- InternalOptions options) {
- this.appInfo = appInfo;
- this.application = appInfo.app.asDirect();
+ AppView<? extends AppInfo> appView, Set<ProguardIfRule> ifRules, InternalOptions options) {
+ this.appView = appView;
+ this.application = appView.appInfo().app.asDirect();
this.rules = Collections.unmodifiableCollection(ifRules);
this.options = options;
}
@@ -341,13 +340,14 @@
Set<DexEncodedMethod> liveMethods,
Set<DexEncodedField> liveFields) throws ExecutionException {
application.timing.begin("Find consequent items for -if rules...");
- Function<DexType, DexClass> definitionForWithLiveTypes = type -> {
- DexClass clazz = appInfo.definitionFor(type);
- if (clazz != null && liveTypes.contains(clazz.type)) {
- return clazz;
- }
- return null;
- };
+ Function<DexType, DexClass> definitionForWithLiveTypes =
+ type -> {
+ DexClass clazz = appView.appInfo().definitionFor(type);
+ if (clazz != null && liveTypes.contains(clazz.type)) {
+ return clazz;
+ }
+ return null;
+ };
try {
List<Future<?>> futures = new ArrayList<>();
if (rules != null) {
@@ -358,7 +358,7 @@
// -keep rule may vary (due to back references). So, we need to try all pairs of -if rule
// and live types.
for (DexType currentLiveType : liveTypes) {
- DexClass currentLiveClass = appInfo.definitionFor(currentLiveType);
+ DexClass currentLiveClass = appView.appInfo().definitionFor(currentLiveType);
if (currentLiveClass == null) {
continue;
}
@@ -550,7 +550,7 @@
out.close();
}
- private static boolean satisfyClassType(ProguardConfigurationRule rule, DexClass clazz) {
+ private boolean satisfyClassType(ProguardConfigurationRule rule, DexClass clazz) {
return rule.getClassType().matches(clazz) != rule.getClassTypeNegated();
}
@@ -723,7 +723,7 @@
if (type.isPrimitiveType()) {
return;
}
- DexClass definition = appInfo.definitionFor(type);
+ DexClass definition = appView.appInfo().definitionFor(type);
if (definition == null || definition.isLibraryClass()) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index f087295..a4f55c3 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -79,7 +79,7 @@
}
static Reporter defaultReporter() {
- return new Reporter(new DefaultDiagnosticsHandler());
+ return new Reporter();
}
/**
diff --git a/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java b/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java
deleted file mode 100644
index 68c2840..0000000
--- a/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.utils;
-
-import com.android.tools.r8.DiagnosticsHandler;
-
-public class DefaultDiagnosticsHandler implements DiagnosticsHandler {
-}
diff --git a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
index 44cfc89..dcf521d 100644
--- a/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
+++ b/src/main/java/com/android/tools/r8/utils/FeatureClassMapping.java
@@ -85,7 +85,7 @@
}
public static FeatureClassMapping fromSpecification(Path file) throws FeatureMappingException {
- return fromSpecification(file, new DefaultDiagnosticsHandler());
+ return fromSpecification(file, new DiagnosticsHandler() {});
}
public static FeatureClassMapping fromSpecification(Path file, DiagnosticsHandler reporter)
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 e0e4227..828a463 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -57,7 +57,7 @@
// Constructor for testing and/or other utilities.
public InternalOptions() {
- reporter = new Reporter(new DefaultDiagnosticsHandler());
+ reporter = new Reporter();
itemFactory = new DexItemFactory();
proguardConfiguration = ProguardConfiguration.defaultConfiguration(itemFactory, reporter);
}
@@ -462,7 +462,6 @@
public boolean nondeterministicCycleElimination = false;
public Set<Inliner.Reason> validInliningReasons = null;
public boolean suppressExperimentalCfBackendWarning = false;
- public boolean removeLocalsTable = false;
}
public boolean canUseInvokePolymorphicOnVarHandle() {
diff --git a/src/main/java/com/android/tools/r8/utils/Reporter.java b/src/main/java/com/android/tools/r8/utils/Reporter.java
index 37f57da..5a1bd06 100644
--- a/src/main/java/com/android/tools/r8/utils/Reporter.java
+++ b/src/main/java/com/android/tools/r8/utils/Reporter.java
@@ -20,6 +20,10 @@
private Diagnostic lastError;
private final Collection<Throwable> suppressedExceptions = new ArrayList<>();
+ public Reporter() {
+ this(new DiagnosticsHandler() {});
+ }
+
public Reporter(DiagnosticsHandler clientHandler) {
this.clientHandler = clientHandler;
}
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java
index 4f0aa2c..244639e 100644
--- a/src/main/java/com/android/tools/r8/utils/StringUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -59,9 +59,10 @@
return builder.toString();
}
- public static void appendNonEmpty(StringBuilder builder, String pre, Object item, String post) {
+ public static boolean appendNonEmpty(
+ StringBuilder builder, String pre, Object item, String post) {
if (item == null) {
- return;
+ return false;
}
String text = item.toString();
if (!text.isEmpty()) {
@@ -72,7 +73,9 @@
if (post != null) {
builder.append(post);
}
+ return true;
}
+ return false;
}
public static StringBuilder appendIndent(StringBuilder builder, String subject, int indent) {
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 97be613..5e70808 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -2,6 +2,9 @@
# 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.
+# Keep line numbers to ensure method mappings in the map file.
+-keepattributes LineNumberTable
+
# Keep the application entry point. Get rid of everything that is not
# reachable from there.
-keep public class classmerging.Test {
@@ -57,6 +60,3 @@
}
-printmapping
-
-# TODO(herhut): Consider supporting merging of inner-class attributes.
-# -keepattributes *
\ No newline at end of file
diff --git a/src/test/examples/shaking1/keep-rules.txt b/src/test/examples/shaking1/keep-rules.txt
index 66cf1c6..82786d5 100644
--- a/src/test/examples/shaking1/keep-rules.txt
+++ b/src/test/examples/shaking1/keep-rules.txt
@@ -2,6 +2,8 @@
# 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.
+-keepattributes LineNumberTable
+
# Keep the application entry point. Get rid of everything that is not
# reachable from there.
-keep public class shaking1.Shaking {
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 403ee70..6f93df4 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -12,8 +12,10 @@
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.SmaliWriter;
@@ -708,7 +710,7 @@
protected ProcessResult runOnVMRaw(AndroidApp app, Class<?> mainClass, Backend backend)
throws IOException {
- return runOnVMRaw(app, mainClass.getCanonicalName(), backend);
+ return runOnVMRaw(app, mainClass.getTypeName(), backend);
}
protected ProcessResult runOnVMRaw(AndroidApp app, String mainClass, Backend backend)
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index f5eaa25..6dde9ed 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
@@ -808,7 +807,7 @@
public static ProguardConfiguration loadProguardConfiguration(
DexItemFactory factory, List<Path> configPaths)
throws IOException, ProguardRuleParserException {
- Reporter reporter = new Reporter(new DefaultDiagnosticsHandler());
+ Reporter reporter = new Reporter();
if (configPaths.isEmpty()) {
return ProguardConfiguration.defaultConfiguration(factory, reporter);
}
@@ -949,7 +948,7 @@
}
public static ProcessResult runJava(Class clazz) throws Exception {
- String main = clazz.getCanonicalName();
+ String main = clazz.getTypeName();
Path path = getClassPathForTests();
return runJava(path, main);
}
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
index 6333638..b85b15b 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Reporter;
import java.nio.file.Path;
@@ -184,7 +183,7 @@
if (frontend == Frontend.CF && compilationMode == CompilationMode.DEBUG) {
// TODO(b/79725635): Investigate why these tests fail on the buildbot.
// Use a Reporter to extract origin info to standard error.
- new Reporter(new DefaultDiagnosticsHandler()).error(e);
+ new Reporter().error(e);
// Print the stack trace since this is not always printed by JUnit.
e.printStackTrace();
Assume.assumeNoException(
diff --git a/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java b/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java
index 308e8d7..e0b953a 100644
--- a/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/ArraySimplificationLineNumberTestRunner.java
@@ -27,7 +27,7 @@
DebugTestConfig d8NoLocals = new D8DebugTestConfig().compileAndAdd(
temp,
Collections.singletonList(ToolHelper.getClassFileForTestClass(CLASS)),
- options -> options.testing.removeLocalsTable = true);
+ options -> options.proguardConfiguration.getKeepAttributes().localVariableTable = false);
new DebugStreamComparator()
.add("CF", streamDebugTest(cf, NAME, NO_FILTER))
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index 99222d0..b6cdb48 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
import com.android.tools.r8.ToolHelper.DexVm;
@@ -79,7 +80,7 @@
* The protocol messages are described here:
* https://docs.oracle.com/javase/8/docs/platform/jpda/jdwp/jdwp-protocol.html
*/
-public abstract class DebugTestBase {
+public abstract class DebugTestBase extends TestBase {
// Set to true to enable verbose logs
private static final boolean DEBUG_TESTS = false;
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index a518a36..7e3c10a 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
@@ -136,8 +135,7 @@
DexApplication application = builder.build();
CollectInfoConsumer consumer = new CollectInfoConsumer();
- InternalOptions options = new InternalOptions(dexItemFactory,
- new Reporter(new DefaultDiagnosticsHandler()));
+ InternalOptions options = new InternalOptions(dexItemFactory, new Reporter());
options.programConsumer = consumer;
ApplicationWriter writer =
new ApplicationWriter(
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 04b6dc0..a459a9c 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -73,17 +74,18 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
return new TestApplication(application, method, code,
ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
@@ -156,14 +158,15 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
return new TestApplication(application, method, code,
ImmutableList.of(codeA), valueNumberGenerator, options);
@@ -236,23 +239,24 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
// Build three copies of a and b for inlining three times.
List<IRCode> additionalCode = new ArrayList<>();
for (int i = 0; i < 3; i++) {
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
additionalCode.add(codeA);
}
for (int i = 0; i < 3; i++) {
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
additionalCode.add(codeB);
}
@@ -372,17 +376,18 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
return new TestApplication(application, method, code,
ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
@@ -486,17 +491,18 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
return new TestApplication(application, method, code,
ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
@@ -599,17 +605,18 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
return new TestApplication(application, method, code,
ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
@@ -713,23 +720,24 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
// Build three copies of a and b for inlining three times.
List<IRCode> additionalCode = new ArrayList<>();
for (int i = 0; i < 3; i++) {
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
additionalCode.add(codeA);
}
for (int i = 0; i < 3; i++) {
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
additionalCode.add(codeB);
}
@@ -872,23 +880,24 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
// Build three copies of a and b for inlining three times.
List<IRCode> additionalCode = new ArrayList<>();
for (int i = 0; i < 3; i++) {
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
additionalCode.add(codeA);
}
for (int i = 0; i < 3; i++) {
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
additionalCode.add(codeB);
}
@@ -1121,17 +1130,18 @@
InternalOptions options = new InternalOptions();
DexApplication application = buildApplication(builder, options);
+ AppInfo appInfo = new AppInfo(application);
// Return the processed method for inspection.
ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
DexEncodedMethod method = getMethod(application, signature);
- IRCode code = method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodA = getMethod(application, signatureA);
- IRCode codeA = methodA.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
DexEncodedMethod methodB = getMethod(application, signatureB);
- IRCode codeB = methodB.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator);
+ IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
return new TestApplication(application, method, code,
ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
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 0cf2f53..86e1d78 100644
--- a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
+++ b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Add;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.ConstNumber;
@@ -20,7 +21,6 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
import com.android.tools.r8.utils.InternalOptions;
@@ -364,8 +364,10 @@
BasicBlock newReturnBlock = iterator.split(code);
// Modify the code to make the inserted block add the constant 10 to the original return
// value.
- Value newConstValue = new Value(test.valueNumberGenerator.next(), ValueType.INT, null);
- Value newReturnValue = new Value(test.valueNumberGenerator.next(), ValueType.INT, null);
+ Value newConstValue =
+ new Value(test.valueNumberGenerator.next(), TypeLatticeElement.INT, null);
+ Value newReturnValue =
+ new Value(test.valueNumberGenerator.next(), TypeLatticeElement.INT, null);
Value oldReturnValue = newReturnBlock.listIterator().next().asReturn().returnValue();
newReturnBlock.listIterator().next().asReturn().returnValue().replaceUsers(newReturnValue);
Instruction constInstruction = new ConstNumber(newConstValue, 10);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
index c618dad..109a6cb 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -120,9 +120,9 @@
DexType mainClass = appInfo.dexItemFactory.createType(
DescriptorUtils.javaTypeToDescriptor(NonNullAfterInvoke.class.getCanonicalName()));
Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- InvokeVirtual.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, true),
- NonNull.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, false),
- NewInstance.class, fromDexType(appInfo, assertionErrorType, false));
+ InvokeVirtual.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, true),
+ NonNull.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, false),
+ NewInstance.class, fromDexType(assertionErrorType, appInfo, false));
forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
});
}
@@ -136,9 +136,9 @@
DexType mainClass = appInfo.dexItemFactory.createType(
DescriptorUtils.javaTypeToDescriptor(NonNullAfterInvoke.class.getCanonicalName()));
Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- InvokeVirtual.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, true),
- NonNull.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, false),
- NewInstance.class, fromDexType(appInfo, assertionErrorType, false));
+ InvokeVirtual.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, true),
+ NonNull.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, false),
+ NewInstance.class, fromDexType(assertionErrorType, appInfo, false));
forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
});
}
@@ -153,8 +153,8 @@
DescriptorUtils.javaTypeToDescriptor(NonNullAfterArrayAccess.class.getCanonicalName()));
Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
// An element inside a non-null array could be null.
- ArrayGet.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, true),
- NewInstance.class, fromDexType(appInfo, assertionErrorType, false));
+ ArrayGet.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, true),
+ NewInstance.class, fromDexType(assertionErrorType, appInfo, false));
forEachOutValue(irCode, (v, l) -> {
if (l.isArrayType()) {
ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
@@ -179,8 +179,8 @@
DescriptorUtils.javaTypeToDescriptor(NonNullAfterArrayAccess.class.getCanonicalName()));
Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
// An element inside a non-null array could be null.
- ArrayGet.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, true),
- NewInstance.class, fromDexType(appInfo, assertionErrorType, false));
+ ArrayGet.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, true),
+ NewInstance.class, fromDexType(assertionErrorType, appInfo, false));
forEachOutValue(irCode, (v, l) -> {
if (l.isArrayType()) {
ArrayTypeLatticeElement lattice = l.asArrayTypeLatticeElement();
@@ -206,11 +206,11 @@
DexType testClass = appInfo.dexItemFactory.createType(
DescriptorUtils.javaTypeToDescriptor(FieldAccessTest.class.getCanonicalName()));
Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- Argument.class, fromDexType(appInfo, testClass, true),
- NonNull.class, fromDexType(appInfo, testClass, false),
+ Argument.class, fromDexType(testClass, appInfo, true),
+ NonNull.class, fromDexType(testClass, appInfo, false),
// instance may not be initialized.
- InstanceGet.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, true),
- NewInstance.class, fromDexType(appInfo, assertionErrorType, false));
+ InstanceGet.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, true),
+ NewInstance.class, fromDexType(assertionErrorType, appInfo, false));
forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
});
}
@@ -226,11 +226,11 @@
DexType testClass = appInfo.dexItemFactory.createType(
DescriptorUtils.javaTypeToDescriptor(FieldAccessTest.class.getCanonicalName()));
Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
- Argument.class, fromDexType(appInfo, testClass, true),
- NonNull.class, fromDexType(appInfo, testClass, false),
+ Argument.class, fromDexType(testClass, appInfo, true),
+ NonNull.class, fromDexType(testClass, appInfo, false),
// instance may not be initialized.
- InstanceGet.class, fromDexType(appInfo, appInfo.dexItemFactory.stringType, true),
- NewInstance.class, fromDexType(appInfo, assertionErrorType, false));
+ InstanceGet.class, fromDexType(appInfo.dexItemFactory.stringType, appInfo, true),
+ NewInstance.class, fromDexType(assertionErrorType, appInfo, false));
forEachOutValue(irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
});
}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
index 75cef4d..fd92348 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
@@ -58,11 +58,10 @@
@RunWith(Parameterized.class)
public class TypeAnalysisTest extends SmaliTestBase {
private static final InternalOptions TEST_OPTIONS = new InternalOptions();
- private static final TypeLatticeElement NULL =
- ReferenceTypeLatticeElement.getNullTypeLatticeElement();
- private static final TypeLatticeElement SINGLE = SingleTypeLatticeElement.getInstance();
- private static final TypeLatticeElement INT = IntTypeLatticeElement.getInstance();
- private static final TypeLatticeElement LONG = LongTypeLatticeElement.getInstance();
+ private static final TypeLatticeElement NULL = TypeLatticeElement.NULL;
+ private static final TypeLatticeElement SINGLE = TypeLatticeElement.SINGLE;
+ private static final TypeLatticeElement INT = TypeLatticeElement.INT;
+ private static final TypeLatticeElement LONG = TypeLatticeElement.LONG;
private final String dirName;
private final String smaliFileName;
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index eb2c54b..8d956a8 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -59,15 +59,23 @@
}
private TopTypeLatticeElement top() {
- return TopTypeLatticeElement.getInstance();
+ return TypeLatticeElement.TOP;
}
private BottomTypeLatticeElement bottom() {
- return BottomTypeLatticeElement.getInstance();
+ return TypeLatticeElement.BOTTOM;
+ }
+
+ private SingleTypeLatticeElement single() {
+ return TypeLatticeElement.SINGLE;
+ }
+
+ private WideTypeLatticeElement wide() {
+ return TypeLatticeElement.WIDE;
}
private TypeLatticeElement element(DexType type) {
- return TypeLatticeElement.fromDexType(appInfo, type, true);
+ return TypeLatticeElement.fromDexType(type, appInfo, true);
}
private ArrayTypeLatticeElement array(int nesting, DexType base) {
@@ -101,6 +109,22 @@
}
@Test
+ public void joinDifferentKindsIsTop() {
+ assertEquals(
+ top(),
+ join(element(factory.intType), element(factory.stringType)));
+ assertEquals(
+ top(),
+ join(element(factory.stringType), element(factory.doubleType)));
+ assertEquals(
+ top(),
+ join(single(), element(factory.objectType)));
+ assertEquals(
+ top(),
+ join(element(factory.objectType), wide()));
+ }
+
+ @Test
public void joinBottomIsUnit() {
DexType charSequence = factory.createType("Ljava/lang/CharSequence;");
assertEquals(
@@ -115,6 +139,19 @@
}
@Test
+ public void joinPrimitiveTypes() {
+ assertEquals(
+ single(),
+ join(element(factory.intType), element(factory.floatType)));
+ assertEquals(
+ wide(),
+ join(element(factory.longType), element(factory.doubleType)));
+ assertEquals(
+ top(),
+ join(element(factory.intType), element(factory.longType)));
+ }
+
+ @Test
public void joinClassTypes() {
DexType charSequence = factory.createType("Ljava/lang/CharSequence;");
assertEquals(
@@ -297,6 +334,11 @@
join(
array(1, factory.intType),
array(1, factory.floatType)));
+ assertEquals(
+ element(factory.objectType),
+ join(
+ array(1, factory.longType),
+ array(1, factory.intType)));
}
@Test
@@ -414,7 +456,7 @@
DexType collection = factory.createType("Ljava/util/Collection;");
DexType set = factory.createType("Ljava/util/Set;");
DexType list = factory.createType("Ljava/util/List;");
- DexType serializable = factory.createType("Ljava/io/Serializable;");
+ DexType serializable = factory.serializableType;
Set<DexType> lub = computeLeastUpperBoundOfInterfaces(appInfo,
ImmutableSet.of(set), ImmutableSet.of(list));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
index 2b92ab1..fb8e674 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
@@ -5,6 +5,7 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.Div;
@@ -16,7 +17,6 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
import com.android.tools.r8.utils.InternalOptions;
@@ -69,14 +69,14 @@
block.setNumber(0);
Position position = Position.testingPosition();
- Value v3 = new Value(3, ValueType.LONG, null);
+ Value v3 = new Value(3, TypeLatticeElement.LONG, null);
v3.setNeedsRegister(true);
new MockLiveIntervals(v3);
Instruction instruction = new ConstNumber(v3, 0);
instruction.setPosition(position);
block.add(instruction);
- Value v0 = new Value(0, ValueType.LONG, null);
+ Value v0 = new Value(0, TypeLatticeElement.LONG, null);
v0.setNeedsRegister(true);
new MockLiveIntervals(v0);
instruction = new ConstNumber(v0, 10);
@@ -87,14 +87,14 @@
instruction.setPosition(position);
block.add(instruction);
- Value v2 = new Value(2, ValueType.INT, null);
+ Value v2 = new Value(2, TypeLatticeElement.INT, null);
v2.setNeedsRegister(true);
new MockLiveIntervals(v2);
instruction = new ConstNumber(v2, 10);
instruction.setPosition(position);
block.add(instruction);
- Value v1 = new Value(1, ValueType.INT, null);
+ Value v1 = new Value(1, TypeLatticeElement.INT, null);
v1.setNeedsRegister(true);
new MockLiveIntervals(v1);
instruction = new Move(v1 ,v2);
@@ -105,7 +105,7 @@
instruction.setPosition(position);
block.add(instruction);
- Value v0_2 = new Value(0, ValueType.LONG, null);
+ Value v0_2 = new Value(0, TypeLatticeElement.LONG, null);
v0_2.setNeedsRegister(true);
new MockLiveIntervals(v0_2);
instruction = new ConstNumber(v0_2, 10);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
index 7b1c369..faff5a4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NullArrayAndNullObjectValueTest.java
@@ -9,13 +9,13 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
import com.android.tools.r8.jasmin.JasminTestBase;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import org.junit.Assert;
@@ -127,7 +127,7 @@
"return");
Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
- jasminBuilder.writeJar(riJar, new DefaultDiagnosticsHandler());
+ jasminBuilder.writeJar(riJar, new DiagnosticsHandler() {});
ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
Assert.assertEquals(riResult.toString(), 0, riResult.exitCode);
@@ -174,7 +174,7 @@
"return");
Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
- jasminBuilder.writeJar(riJar, new DefaultDiagnosticsHandler());
+ jasminBuilder.writeJar(riJar, new DiagnosticsHandler() {});
ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
Assert.assertEquals(riResult.toString(), 1, riResult.exitCode);
assertTrue(riResult.stderr.contains("VerifyError"));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
index 6470876..d254847 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
@@ -6,6 +6,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.ConstNumber;
@@ -19,7 +21,6 @@
import com.android.tools.r8.ir.code.Throw;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableList;
import java.util.LinkedList;
@@ -49,7 +50,7 @@
block2.setFilledForTesting();
BasicBlock block1 = new BasicBlock();
block1.setNumber(1);
- Value value = new Value(0, ValueType.INT, null);
+ Value value = new Value(0, TypeLatticeElement.INT, null);
Instruction number = new ConstNumber(value, 0);
number.setPosition(position);
block1.add(number);
@@ -110,7 +111,7 @@
BasicBlock block0 = new BasicBlock();
block0.setNumber(0);
- Value value = new Value(0, ValueType.OBJECT, null);
+ Value value = new Value(0, TypeLatticeElement.fromDexType(DexItemFactory.catchAllType), null);
instruction = new Argument(value);
instruction.setPosition(position);
block0.add(instruction);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTest.java
new file mode 100644
index 0000000..6d6b4c7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTest.java
@@ -0,0 +1,55 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.optimize.checkcast;
+
+import com.android.tools.r8.NeverInline;
+
+class A {
+ @NeverInline
+ @Override
+ public String toString() {
+ return "A";
+ }
+}
+
+class B extends A {
+ @NeverInline
+ @Override
+ public String toString() {
+ return super.toString() + "B";
+ }
+}
+
+class C extends B {
+ @NeverInline
+ @Override
+ public String toString() {
+ return super.toString() + "C";
+ }
+}
+
+class CheckCastDebugTest {
+ @NeverInline
+ static void differentLocals() {
+ Object obj = new C();
+ A a = (A) obj;
+ B b = (B) a;
+ C c = (C) b;
+ System.out.println(c.toString());
+ }
+
+ @NeverInline
+ static void sameLocal() {
+ Object obj = new C();
+ obj = (A) obj;
+ obj = (B) obj;
+ obj = (C) obj;
+ System.out.println(obj.toString());
+ }
+
+ public static void main(String[] args) {
+ differentLocals();
+ sameLocal();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
new file mode 100644
index 0000000..d7a5732
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
@@ -0,0 +1,173 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.optimize.checkcast;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.debug.CfDebugTestConfig;
+import com.android.tools.r8.debug.DebugTestBase;
+import com.android.tools.r8.debug.DebugTestConfig;
+import com.android.tools.r8.debug.DexDebugTestConfig;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Streams;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class CheckCastDebugTestRunner extends DebugTestBase {
+ private static final Class<?> MAIN = CheckCastDebugTest.class;
+ private final Backend backend;
+
+ private Path r8Out;
+ private CodeInspector inspector;
+
+ @Parameterized.Parameters(name = "Backend: {0}")
+ public static Collection<Backend> data() {
+ return Arrays.asList(Backend.values());
+ }
+
+ public CheckCastDebugTestRunner(Backend backend) {
+ this.backend = backend;
+ }
+
+ private static int testCounter = 0;
+
+ @Before
+ public void setUp() throws Exception {
+ AndroidApp app = readClasses(NeverInline.class, A.class, B.class, C.class, MAIN);
+ r8Out = temp.newFile(String.format("r8Out-%s-%d.zip", backend, testCounter++)).toPath();
+ R8Command.Builder builder = ToolHelper.prepareR8CommandBuilder(app);
+ if (backend == Backend.DEX) {
+ builder.setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(r8Out));
+ } else {
+ assert backend == Backend.CF;
+ builder.setProgramConsumer(new ClassFileConsumer.ArchiveConsumer(r8Out));
+ }
+ builder.addProguardConfiguration(
+ ImmutableList.of(
+ "-dontobfuscate",
+ keepMainProguardConfigurationWithInliningAnnotation(MAIN)),
+ Origin.unknown());
+ builder.setMode(CompilationMode.DEBUG);
+ ToolHelper.allowTestProguardOptions(builder);
+ ToolHelper.runR8(builder.build(), o -> o.enableVerticalClassMerging = false);
+ inspector = new CodeInspector(r8Out);
+ ClassSubject classSubject = inspector.clazz(MAIN);
+ assertThat(classSubject, isPresent());
+ }
+
+ @Ignore("todo: jsjeon")
+ @Test
+ public void test_differentLocals() throws Throwable {
+ ClassSubject classSubject = inspector.clazz(MAIN);
+ MethodSubject method = classSubject.method("void", "differentLocals", ImmutableList.of());
+ assertThat(method, isPresent());
+ long count =
+ Streams.stream(method.iterateInstructions(InstructionSubject::isCheckCast)).count();
+ assertEquals(1, count);
+
+ DebugTestConfig config = backend == Backend.CF
+ ? new CfDebugTestConfig()
+ : new DexDebugTestConfig();
+ config.addPaths(r8Out);
+ runDebugTest(config, MAIN.getCanonicalName(),
+ // Object obj = new C();
+ breakpoint(MAIN.getCanonicalName(), "differentLocals", "()V", 35),
+ run(),
+ checkNoLocal("obj"),
+ checkNoLocal("a"),
+ checkNoLocal("b"),
+ checkNoLocal("c"),
+ // A a = (A) obj;
+ breakpoint(MAIN.getCanonicalName(), "differentLocals", "()V", 36),
+ run(),
+ checkLocal("obj"),
+ checkNoLocal("a"),
+ checkNoLocal("b"),
+ checkNoLocal("c"),
+ // B b = (B) a;
+ breakpoint(MAIN.getCanonicalName(), "differentLocals", "()V", 37),
+ run(),
+ checkLocal("obj"),
+ checkLocal("a"),
+ checkNoLocal("b"),
+ checkNoLocal("c"),
+ // C c = (C) b;
+ breakpoint(MAIN.getCanonicalName(), "differentLocals", "()V", 38),
+ run(),
+ checkLocal("obj"),
+ checkLocal("a"),
+ checkLocal("b"),
+ checkNoLocal("c"),
+ // System.out.println(c.toString());
+ breakpoint(MAIN.getCanonicalName(), "differentLocals", "()V", 39),
+ run(),
+ checkLocal("obj"),
+ checkLocal("a"),
+ checkLocal("b"),
+ checkLocal("c"),
+ run()
+ );
+ }
+
+ @Ignore("todo: jsjeon")
+ @Test
+ public void test_sameLocal() throws Throwable {
+ ClassSubject classSubject = inspector.clazz(MAIN);
+ MethodSubject method = classSubject.method("void", "sameLocal", ImmutableList.of());
+ assertThat(method, isPresent());
+ long count =
+ Streams.stream(method.iterateInstructions(InstructionSubject::isCheckCast)).count();
+ assertEquals(1, count);
+
+ DebugTestConfig config = backend == Backend.CF
+ ? new CfDebugTestConfig()
+ : new DexDebugTestConfig();
+ config.addPaths(r8Out);
+ runDebugTest(config, MAIN.getCanonicalName(),
+ // Object obj = new C();
+ breakpoint(MAIN.getCanonicalName(), "sameLocal", "()V", 44),
+ run(),
+ checkNoLocal("obj"),
+ // obj = (A) obj;
+ breakpoint(MAIN.getCanonicalName(), "sameLocal", "()V", 45),
+ run(),
+ checkLocal("obj"),
+ // obj = (B) obj;
+ breakpoint(MAIN.getCanonicalName(), "sameLocal", "()V", 46),
+ run(),
+ checkLocal("obj"),
+ // obj = (C) obj;
+ breakpoint(MAIN.getCanonicalName(), "sameLocal", "()V", 47),
+ run(),
+ checkLocal("obj"),
+ // System.out.println(obj.toString());
+ breakpoint(MAIN.getCanonicalName(), "sameLocal", "()V", 48),
+ run(),
+ checkLocal("obj"),
+ run()
+ );
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java
index b141955..c953515 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java
@@ -99,7 +99,7 @@
}
@Test
- public void downCasts() throws Exception {
+ public void downCasts_noLocal() throws Exception {
JasminBuilder builder = new JasminBuilder();
// C < B < A
ClassBuilder a = builder.addClass("A");
@@ -133,6 +133,91 @@
}
@Test
+ public void downCasts_differentLocals() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+ // C < B < A
+ ClassBuilder a = builder.addClass("A");
+ a.addDefaultConstructor();
+ ClassBuilder b = builder.addClass("B", "A");
+ b.addDefaultConstructor();
+ ClassBuilder c = builder.addClass("C", "B");
+ c.addDefaultConstructor();
+ ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
+ MethodSignature main = classBuilder.addMainMethod(
+ ".limit stack 3",
+ ".limit locals 3",
+ ".var 0 is a LA; from Label1 to Label2",
+ ".var 1 is b LB; from Label1 to Label2",
+ ".var 2 is c LC; from Label1 to Label2",
+ "Label1:",
+ "new A",
+ "dup",
+ "invokespecial A/<init>()V",
+ "astore_0",
+ "aload_0",
+ "checkcast B", // Gone
+ "astore_1",
+ "aload_1",
+ "checkcast C", // Should be kept to preserve cast exception
+ "astore_2",
+ "Label2:",
+ "return");
+
+ List<String> pgConfigs = ImmutableList.of(
+ "-keep class " + CLASS_NAME + " { *; }",
+ "-keep class A { *; }",
+ "-keep class B { *; }",
+ "-keep class C { *; }",
+ "-dontoptimize",
+ "-dontshrink");
+ AndroidApp app = compileWithR8InDebugMode(builder, pgConfigs, null, backend);
+
+ checkCheckCasts(app, main, "C");
+ checkRuntimeException(builder, app, CLASS_NAME, "ClassCastException");
+ }
+
+ @Test
+ public void downCasts_sameLocal() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+ // C < B < A
+ ClassBuilder a = builder.addClass("A");
+ a.addDefaultConstructor();
+ ClassBuilder b = builder.addClass("B", "A");
+ b.addDefaultConstructor();
+ ClassBuilder c = builder.addClass("C", "B");
+ c.addDefaultConstructor();
+ ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
+ MethodSignature main = classBuilder.addMainMethod(
+ ".limit stack 3",
+ ".limit locals 1",
+ ".var 0 is a LA; from Label1 to Label2",
+ "Label1:",
+ "new A",
+ "dup",
+ "invokespecial A/<init>()V",
+ "astore_0",
+ "aload_0",
+ "checkcast B", // Gone
+ "astore_0",
+ "aload_0",
+ "checkcast C", // Should be kept to preserve cast exception
+ "Label2:",
+ "return");
+
+ List<String> pgConfigs = ImmutableList.of(
+ "-keep class " + CLASS_NAME + " { *; }",
+ "-keep class A { *; }",
+ "-keep class B { *; }",
+ "-keep class C { *; }",
+ "-dontoptimize",
+ "-dontshrink");
+ AndroidApp app = compileWithR8InDebugMode(builder, pgConfigs, null, backend);
+
+ checkCheckCasts(app, main, "C");
+ checkRuntimeException(builder, app, CLASS_NAME, "ClassCastException");
+ }
+
+ @Test
public void bothUpAndDowncast() throws Exception {
JasminBuilder builder = new JasminBuilder();
ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
@@ -180,7 +265,7 @@
"-dontshrink");
AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
- checkCheckCasts(app, main, "Example");
+ checkCheckCasts(app, main, null);
checkRuntimeException(builder, app, CLASS_NAME, "NullPointerException");
}
@@ -201,6 +286,7 @@
assertTrue(!found && instruction.isCheckCast(maybeType));
found = true;
}
+ assertTrue(found);
}
private void checkRuntime(JasminBuilder builder, AndroidApp app, String className)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java
new file mode 100644
index 0000000..d52725e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.checkcast;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class RemoveCheckCastAfterClassInlining extends TestBase {
+
+ @Test
+ public void test() throws Exception {
+ AndroidApp input = readClasses(Lambda.class, Lambda.Consumer.class);
+ AndroidApp output =
+ compileWithR8(
+ input,
+ keepMainProguardConfiguration(Lambda.class),
+ options -> options.enableMinification = false);
+
+ // Extract main method.
+ CodeInspector inspector = new CodeInspector(output);
+ ClassSubject classSubject = inspector.clazz(Lambda.class);
+ MethodSubject methodSubject = classSubject.mainMethod();
+ assertThat(methodSubject, isPresent());
+
+ DexEncodedMethod method = methodSubject.getMethod();
+ assertTrue(method.hasCode());
+
+ DexCode code = method.getCode().asDexCode();
+ int numberOfConstStringInstructions = 0;
+ for (Instruction instruction : code.instructions) {
+ // Make sure that we do not load a const-string and then subsequently use a check-cast
+ // instruction to check if it is actually a string.
+ assertFalse(instruction.isCheckCast());
+ if (instruction.isConstString()) {
+ numberOfConstStringInstructions++;
+ }
+ }
+
+ // Sanity check that load() was actually inlined.
+ assertThat(
+ classSubject.method("void", "load", ImmutableList.of(Lambda.Consumer.class.getName())),
+ not(isPresent()));
+ assertEquals(2, numberOfConstStringInstructions);
+ }
+}
+
+class Lambda {
+
+ interface Consumer<T> {
+ void accept(T value);
+ }
+
+ public static void main(String... args) {
+ load(s -> System.out.println(s));
+ // Other code…
+ load(s -> System.out.println(s));
+ }
+
+ public static void load(Consumer<String> c) {
+ c.accept("Hello!");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
index caa697b..e65ebca 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
@@ -40,6 +40,7 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FieldAccessInstructionSubject;
@@ -429,10 +430,11 @@
}
private String getProguardConfig(String main) {
- return keepMainProguardConfiguration(main)
- + "\n"
- + "-dontobfuscate\n"
- + "-allowaccessmodification";
+ return StringUtils.joinLines(
+ keepMainProguardConfiguration(main),
+ "-dontobfuscate",
+ "-allowaccessmodification",
+ "-keepattributes LineNumberTable");
}
private void configure(InternalOptions options) {
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
index 8102882..6d824ec 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
@@ -6,12 +6,12 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Add;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.InternalOptions;
import org.junit.Test;
@@ -47,13 +47,13 @@
@Test
public void equalityOfConstantOperands() {
RegisterAllocator allocator = new MockRegisterAllocator();
- Value value0 = new Value(0, ValueType.INT, null);
+ Value value0 = new Value(0, TypeLatticeElement.INT, null);
ConstNumber const0 = new ConstNumber(value0, 0);
- Value value1 = new Value(1, ValueType.INT, null);
+ Value value1 = new Value(1, TypeLatticeElement.INT, null);
ConstNumber const1 = new ConstNumber(value1, 1);
- Value value2 = new Value(2, ValueType.INT, null);
+ Value value2 = new Value(2, TypeLatticeElement.INT, null);
ConstNumber const2 = new ConstNumber(value2, 2);
- Value value3 = new Value(2, ValueType.INT, null);
+ Value value3 = new Value(2, TypeLatticeElement.INT, null);
Add add0 = new Add(NumericType.INT, value3, value0, value1);
add0.setPosition(Position.none());
Add add1 = new Add(NumericType.INT, value3, value0, value2);
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
index 9866b34..ddbe2c8 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
@@ -4,10 +4,10 @@
package com.android.tools.r8.ir.regalloc;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
-import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
import com.android.tools.r8.smali.SmaliTestBase;
@@ -61,18 +61,21 @@
MyRegisterAllocator allocator = new MyRegisterAllocator(code, options);
// Setup live an inactive live interval with ranges [0, 10[ and [20, 30[ with only
// uses in the first interval and which is linked to another interval.
- LiveIntervals inactiveIntervals = new LiveIntervals(new Value(0, ValueType.INT, null));
+ LiveIntervals inactiveIntervals =
+ new LiveIntervals(new Value(0, TypeLatticeElement.INT, null));
inactiveIntervals.addRange(new LiveRange(0, 10));
inactiveIntervals.addUse(new LiveIntervalsUse(0, 10));
inactiveIntervals.addUse(new LiveIntervalsUse(4, 10));
inactiveIntervals.addRange(new LiveRange(20, 30));
inactiveIntervals.setRegister(0);
- LiveIntervals linked = new LiveIntervals(new Value(1, ValueType.INT, null));
+ LiveIntervals linked =
+ new LiveIntervals(new Value(1, TypeLatticeElement.INT, null));
linked.setRegister(1);
inactiveIntervals.link(linked);
allocator.addInactiveIntervals(inactiveIntervals);
// Setup an unhandled interval that overlaps the inactive interval.
- LiveIntervals unhandledIntervals = new LiveIntervals(new Value(2, ValueType.INT, null));
+ LiveIntervals unhandledIntervals =
+ new LiveIntervals(new Value(2, TypeLatticeElement.INT, null));
unhandledIntervals.addRange(new LiveRange(12, 24));
// Split the overlapping inactive intervals and check that after the split, the second
// part of the inactive interval is unhandled and will therefore get a new register
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 f106793..cfc49fe 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.fail;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
@@ -106,6 +107,21 @@
return ToolHelper.runR8(builder.build(), optionsConsumer);
}
+ protected AndroidApp compileWithR8InDebugMode(
+ JasminBuilder builder,
+ List<String> proguardConfigs,
+ Consumer<InternalOptions> optionsConsumer,
+ Backend backend)
+ throws Exception {
+ R8Command command =
+ ToolHelper.prepareR8CommandBuilder(builder.build(), emptyConsumer(backend))
+ .addLibraryFiles(runtimeJar(backend))
+ .addProguardConfiguration(proguardConfigs, Origin.unknown())
+ .setMode(CompilationMode.DEBUG)
+ .build();
+ return ToolHelper.runR8(command, optionsConsumer);
+ }
+
protected AndroidApp compileWithR8(
JasminBuilder builder,
List<String> proguardConfigs,
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 67afdd7..6b7a7c2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -10,7 +10,6 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.code.InvokeStatic;
import com.android.tools.r8.code.NewInstance;
import com.android.tools.r8.code.SgetObject;
import com.android.tools.r8.graph.DexClass;
@@ -19,9 +18,12 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import com.google.common.collect.Streams;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -229,8 +231,8 @@
private List<String> collectStaticCalls(ClassSubject clazz, String methodName, String... params) {
assertNotNull(clazz);
MethodSignature signature = new MethodSignature(methodName, "void", params);
- DexCode code = clazz.method(signature).getMethod().getCode().asDexCode();
- return filterInstructionKind(code, InvokeStatic.class)
+ MethodSubject method = clazz.method(signature);
+ return Streams.stream(method.iterateInstructions(InstructionSubject::isInvokeStatic))
.map(insn -> insn.getMethod().toSourceString())
.sorted()
.collect(Collectors.toList());
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 43bf86e..4f91609 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -59,7 +59,6 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -660,7 +659,7 @@
List<String> classes, int minApi, boolean intermediate, int methodCount)
throws IOException, ExecutionException {
return generateApplication(
- classes, minApi, intermediate, methodCount, new DefaultDiagnosticsHandler());
+ classes, minApi, intermediate, methodCount, new DiagnosticsHandler() {});
}
private static AndroidApp generateApplication(
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java b/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java
new file mode 100644
index 0000000..b280242
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.memberrebinding;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.R8Command.Builder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class IndirectSuperInterfaceTest extends TestBase {
+
+ public interface Interface {
+ @NeverInline
+ default void foo() {
+ System.out.print("Interface::foo ");
+ }
+ }
+
+ public static class A implements Interface {
+ // Intentionally empty.
+ }
+
+ public static class B extends A {
+ @Override
+ public void foo() {
+ System.out.print("B::foo ");
+ super.foo();
+ }
+
+ public static void main(String[] args) {
+ new B().foo();
+ }
+ }
+
+ private final Backend backend;
+
+ @Parameters(name = "{0}")
+ public static Backend[] setup() {
+ return new Backend[] {Backend.CF, Backend.DEX};
+ }
+
+ public IndirectSuperInterfaceTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void test() throws Exception {
+ String expected = "B::foo Interface::foo ";
+ String reference = runOnJava(B.class);
+ assertEquals(expected, reference);
+
+ AndroidAppConsumers sink = new AndroidAppConsumers();
+ Builder builder =
+ R8Command.builder()
+ .addClassProgramData(ToolHelper.getClassAsBytes(Interface.class), Origin.unknown())
+ .addClassProgramData(ToolHelper.getClassAsBytes(A.class), Origin.unknown())
+ .addClassProgramData(ToolHelper.getClassAsBytes(B.class), Origin.unknown())
+ .setProgramConsumer(sink.wrapProgramConsumer(emptyConsumer(backend)))
+ .addLibraryFiles(runtimeJar(backend))
+ .addProguardConfiguration(
+ ImmutableList.of(
+ "-keep class " + Interface.class.getTypeName(),
+ "-keep class " + A.class.getTypeName(),
+ keepMainProguardConfigurationWithInliningAnnotation(B.class)),
+ Origin.unknown());
+ ToolHelper.allowTestProguardOptions(builder);
+ if (backend == Backend.DEX) {
+ builder.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm().getLevel());
+ }
+ R8.run(builder.build());
+
+ ProcessResult result = runOnVMRaw(sink.build(), B.class, backend);
+
+ // TODO(b/117407667): Assert the test does not fail once fixed.
+ assertTrue(result.toString(), result.exitCode == (backend == Backend.DEX ? 0 : 1));
+ if (result.exitCode == 0) {
+ assertEquals(reference, result.stdout);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/EnumMinification.java b/src/test/java/com/android/tools/r8/naming/EnumMinification.java
index 3f6e4e7..a8708eb 100644
--- a/src/test/java/com/android/tools/r8/naming/EnumMinification.java
+++ b/src/test/java/com/android/tools/r8/naming/EnumMinification.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
@@ -55,7 +56,9 @@
result.stderr,
containsString(
backend == Backend.DEX
- ? "java.lang.NoSuchMethodException"
+ ? ToolHelper.getDexVm().isNewerThan(DexVm.ART_4_4_4_HOST)
+ ? "java.lang.NoSuchMethodException"
+ : "java.lang.NullPointerException"
: "java.lang.IllegalArgumentException"));
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
index 3240365..8d62033 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
@@ -498,7 +498,7 @@
testSingleClass("Outer", "X", diagnostics -> {
assertEquals(1, diagnostics.warnings.size());
DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
- "Invalid signature for class Outer", "Expected L at position 1");
+ "Invalid signature 'X' for class Outer", "Expected L at position 1");
}, inspector -> noSignatureAttribute(inspector.clazz("Outer")));
}
@@ -507,7 +507,7 @@
testSingleClass("Outer", "<L", diagnostics -> {
assertEquals(1, diagnostics.warnings.size());
DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
- "Invalid signature for class Outer", "Unexpected end of signature at position 3");
+ "Invalid signature '<L' for class Outer", "Unexpected end of signature at position 3");
}, inspector -> noSignatureAttribute(inspector.clazz("Outer")));
}
@@ -516,7 +516,7 @@
testSingleClass("Outer$ExtendsInner", "X", diagnostics -> {
assertEquals(1, diagnostics.warnings.size());
DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
- "Invalid signature for class Outer$ExtendsInner", "Expected L at position 1");
+ "Invalid signature 'X' for class Outer$ExtendsInner", "Expected L at position 1");
}, inspector -> noSignatureAttribute(inspector.clazz("Outer$ExtendsInner")));
}
@@ -525,7 +525,7 @@
testSingleClass("Outer$Inner$ExtendsInnerInner", "X", diagnostics -> {
assertEquals(1, diagnostics.warnings.size());
DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
- "Invalid signature for class Outer$Inner$ExtendsInnerInner",
+ "Invalid signature 'X' for class Outer$Inner$ExtendsInnerInner",
"Expected L at position 1");
}, inspector -> noSignatureAttribute(inspector.clazz("Outer$Inner$ExtendsInnerInner")));
}
@@ -548,8 +548,11 @@
String signature = "LOuter<TT;>.com/example/Inner;";
testSingleClass("Outer$ExtendsInner", signature, diagnostics -> {
assertEquals(1, diagnostics.warnings.size());
- DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
- "Invalid signature for class Outer$ExtendsInner", "Expected ; at position 16");
+ DiagnosticsChecker.checkDiagnostic(
+ diagnostics.warnings.get(0),
+ this::isOriginUnknown,
+ "Invalid signature '" + signature + "' for class Outer$ExtendsInner",
+ "Expected ; at position 16");
}, inspector -> {
noSignatureAttribute(inspector.clazz("Outer$ExtendsInner"));
});
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
index 4c81632..f73b8d2 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
@@ -278,7 +278,7 @@
assertEquals(1, diagnostics.warnings.size());
// TODO(sgjesse): The position 2 reported here is one off.
DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
- "Invalid signature for field",
+ "Invalid signature 'X' for field",
"java.lang.String Fields.anX",
"Expected L, [ or T at position 2");
}, inspector -> noSignatureAttribute(lookupAnX(inspector)));
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
index a1ab483..d9d4774 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
@@ -299,7 +299,7 @@
testSingleMethod("generic", "X", diagnostics -> {
assertEquals(1, diagnostics.warnings.size());
DiagnosticsChecker.checkDiagnostic(diagnostics.warnings.get(0), this::isOriginUnknown,
- "Invalid signature for method",
+ "Invalid signature 'X' for method",
"java.lang.Throwable Methods.generic(java.lang.Throwable, Methods$Inner)",
"Expected ( at position 1");
}, inspector -> noSignatureAttribute(lookupGeneric(inspector)));
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index 932c09b..719fe80 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.shaking.RootSetBuilder;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.ThreadUtils;
@@ -70,25 +69,21 @@
throws IOException, ProguardRuleParserException, ExecutionException {
ProguardConfiguration configuration =
ToolHelper.loadProguardConfiguration(dexItemFactory, configPaths);
- InternalOptions options = new InternalOptions(configuration,
- new Reporter(new DefaultDiagnosticsHandler()));
+ InternalOptions options = new InternalOptions(configuration, new Reporter());
ExecutorService executor = ThreadUtils.getExecutorService(1);
- AppInfoWithSubtyping appInfo = appView.appInfo();
- RootSet rootSet = new RootSetBuilder(appInfo, program, configuration.getRules(), options)
- .run(executor);
+ RootSet rootSet =
+ new RootSetBuilder(appView, program, configuration.getRules(), options).run(executor);
if (options.proguardConfiguration.isAccessModificationAllowed()) {
ClassAndMemberPublicizer.run(executor, timing, program, appView, rootSet);
rootSet =
- new RootSetBuilder(appInfo, program, configuration.getRules(), options).run(executor);
+ new RootSetBuilder(appView, program, configuration.getRules(), options).run(executor);
}
- Enqueuer enqueuer =
- new Enqueuer(
- appInfo, GraphLense.getIdentityLense(), options, options.forceProguardCompatibility);
- appInfo = enqueuer.traceApplication(rootSet, executor, timing);
+ Enqueuer enqueuer = new Enqueuer(appView, options, options.forceProguardCompatibility);
+ AppInfoWithSubtyping appInfo = enqueuer.traceApplication(rootSet, executor, timing);
return new Minifier(appInfo.withLiveness(), rootSet, Collections.emptySet(), options)
.run(timing);
}
diff --git a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
index 9ccc94b..5127a59 100644
--- a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
+++ b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
@@ -112,6 +112,7 @@
+ " <methods>;"
+ "}",
"-printmapping",
+ "-keepattributes LineNumberTable",
reflectionRules),
Origin.unknown())
.setOutput(out, outputMode(backend));
diff --git a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingTest.java
similarity index 98%
rename from src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
rename to src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingTest.java
index 7ce8a05..3b552c8 100644
--- a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingTest.java
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.naming;
+package com.android.tools.r8.naming.applymapping;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -18,6 +18,7 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/CompositionalLenseTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/CompositionalLenseTest.java
similarity index 89%
rename from src/test/java/com/android/tools/r8/memberrebinding/CompositionalLenseTest.java
rename to src/test/java/com/android/tools/r8/naming/applymapping/CompositionalLenseTest.java
index 711ae60..446a481 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/CompositionalLenseTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/CompositionalLenseTest.java
@@ -1,7 +1,7 @@
// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.memberrebinding;
+package com.android.tools.r8.naming.applymapping;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.junit.Assert.assertEquals;
@@ -44,7 +44,7 @@
// Sub#foo ~> Base#foo by member rebinding analysis
}
-class TestMain {
+class CompositionalLenseTestMain {
public static void main(String[] args) {
// Without regard to the order of member rebinding and apply mapping,
// this call should be mapped to X.bar(), not Y.bar() nor Base.foo().
@@ -55,7 +55,7 @@
@RunWith(Parameterized.class)
public class CompositionalLenseTest extends TestBase {
private final static List<Class> CLASSES =
- ImmutableList.of(Base.class, Sub.class, TestMain.class);
+ ImmutableList.of(Base.class, Sub.class, CompositionalLenseTestMain.class);
private Backend backend;
@@ -72,9 +72,9 @@
public void test() throws Exception {
Path mapPath = temp.newFile("test-mapping.txt").toPath();
List<String> pgMap = ImmutableList.of(
- "com.android.tools.r8.memberrebinding.Base -> X:",
+ "com.android.tools.r8.naming.applymapping.Base -> X:",
" void foo() -> bar",
- "com.android.tools.r8.memberrebinding.Sub -> Y:",
+ "com.android.tools.r8.naming.applymapping.Sub -> Y:",
" void foo() -> bar"
);
FileUtils.writeTextFile(mapPath, pgMap);
@@ -84,7 +84,7 @@
builder
.addProguardConfiguration(
ImmutableList.of(
- keepMainProguardConfiguration(TestMain.class),
+ keepMainProguardConfiguration(CompositionalLenseTestMain.class),
"-applymapping " + mapPath,
"-dontobfuscate"), // to use the renamed names in test-mapping.txt
Origin.unknown())
@@ -97,7 +97,7 @@
options.enableVerticalClassMerging = false;
});
CodeInspector codeInspector = new CodeInspector(processedApp);
- ClassSubject classSubject = codeInspector.clazz(TestMain.class);
+ ClassSubject classSubject = codeInspector.clazz(CompositionalLenseTestMain.class);
assertThat(classSubject, isPresent());
MethodSubject methodSubject = classSubject.method(CodeInspector.MAIN);
assertThat(methodSubject, isPresent());
diff --git a/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java b/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java
index dd1ee60..db3f356 100644
--- a/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java
+++ b/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java
@@ -100,22 +100,13 @@
this.minify = minify;
}
- private String run(AndroidApp app, String main) throws IOException {
- if (generatesDex(shrinker)) {
- return runOnArt(app, main);
- } else {
- assert generatesCf(shrinker);
- return runOnJava(app, main, Collections.emptyList());
- }
- }
-
private static boolean vmVersionIgnored() {
return !ToolHelper.getDexVm().getVersion().isAtLeast(Version.V7_0_0);
}
@Test
public void test_keepAll() throws Exception {
- Assume.assumeFalse(generatesDex(shrinker) && vmVersionIgnored());
+ Assume.assumeFalse(shrinker.generatesDex() && vmVersionIgnored());
Class mainClass = TestMain.class;
String keep = !minify ? "-keep" : "-keep,allowobfuscation";
List<String> config = ImmutableList.of(
@@ -138,10 +129,10 @@
AndroidApp app = runShrinker(shrinker, CLASSES, config);
assertEquals(
StringUtils.withNativeLineSeparator("123451234567\nABC\n"),
- run(app, mainClass.getCanonicalName()));
+ runOnVM(app, mainClass.getCanonicalName(), shrinker.toBackend()));
CodeInspector codeInspector =
- isR8(shrinker) ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
+ shrinker.isR8() ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
ClassSubject testClass = codeInspector.clazz(TestClass.class);
assertThat(testClass, isPresent());
@@ -149,7 +140,7 @@
MethodSubject staticMethod = testClass.method("void", "unused", ImmutableList.of());
assertThat(staticMethod, isPresent());
assertEquals(minify, staticMethod.isRenamed());
- if (isR8(shrinker)) {
+ if (shrinker.isR8()) {
assertEquals(allowAccessModification, staticMethod.getMethod().accessFlags.isPublic());
} else {
assertFalse(staticMethod.getMethod().accessFlags.isPublic());
@@ -159,14 +150,14 @@
staticMethod = testClass.method("java.lang.String", "staticMethod", ImmutableList.of());
assertThat(staticMethod, isPresent());
assertEquals(minify, staticMethod.isRenamed());
- boolean publicizeCondition = isR8(shrinker) ? allowAccessModification
+ boolean publicizeCondition = shrinker.isR8() ? allowAccessModification
: minify && repackagePrefix != null && allowAccessModification;
assertEquals(publicizeCondition, staticMethod.getMethod().accessFlags.isPublic());
}
@Test
public void test_keepNonPublic() throws Exception {
- Assume.assumeFalse(generatesDex(shrinker) && vmVersionIgnored());
+ Assume.assumeFalse(shrinker.generatesDex() && vmVersionIgnored());
Class mainClass = TestMain.class;
String keep = !minify ? "-keep" : "-keep,allowobfuscation";
List<String> config = ImmutableList.of(
@@ -189,10 +180,10 @@
AndroidApp app = runShrinker(shrinker, CLASSES, config);
assertEquals(
StringUtils.withNativeLineSeparator("123451234567\nABC\n"),
- run(app, mainClass.getCanonicalName()));
+ runOnVM(app, mainClass.getCanonicalName(), shrinker.toBackend()));
CodeInspector codeInspector =
- isR8(shrinker) ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
+ shrinker.isR8() ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
ClassSubject testClass = codeInspector.clazz(TestClass.class);
assertThat(testClass, isPresent());
@@ -200,7 +191,7 @@
MethodSubject staticMethod = testClass.method("void", "unused", ImmutableList.of());
assertThat(staticMethod, isPresent());
assertEquals(minify, staticMethod.isRenamed());
- if (isR8(shrinker)) {
+ if (shrinker.isR8()) {
assertEquals(allowAccessModification, staticMethod.getMethod().accessFlags.isPublic());
} else {
assertFalse(staticMethod.getMethod().accessFlags.isPublic());
@@ -210,14 +201,14 @@
staticMethod = testClass.method("java.lang.String", "staticMethod", ImmutableList.of());
assertThat(staticMethod, isPresent());
assertEquals(minify, staticMethod.isRenamed());
- boolean publicizeCondition = isR8(shrinker) ? allowAccessModification
+ boolean publicizeCondition = shrinker.isR8() ? allowAccessModification
: minify && repackagePrefix != null && allowAccessModification;
assertEquals(publicizeCondition, staticMethod.getMethod().accessFlags.isPublic());
}
@Test
public void test_keepPublic() throws Exception {
- Assume.assumeFalse(generatesDex(shrinker) && vmVersionIgnored());
+ Assume.assumeFalse(shrinker.generatesDex() && vmVersionIgnored());
Class mainClass = TestMain.class;
String keep = !minify ? "-keep" : "-keep,allowobfuscation";
Iterable<String> config = ImmutableList.of(
@@ -236,7 +227,7 @@
"}",
"-dontwarn java.lang.invoke.*"
);
- if (isR8(shrinker)) {
+ if (shrinker.isR8()) {
config = Iterables.concat(config, ImmutableList.of(
"-neverinline class " + TestClass.class.getCanonicalName() + " {",
" * staticMethod();",
@@ -247,10 +238,10 @@
AndroidApp app = runShrinker(shrinker, CLASSES, config);
assertEquals(
StringUtils.withNativeLineSeparator("123451234567\nABC\n"),
- run(app, mainClass.getCanonicalName()));
+ runOnVM(app, mainClass.getCanonicalName(), shrinker.toBackend()));
CodeInspector codeInspector =
- isR8(shrinker) ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
+ shrinker.isR8() ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
ClassSubject testClass = codeInspector.clazz(TestClass.class);
assertThat(testClass, isPresent());
@@ -262,7 +253,7 @@
staticMethod = testClass.method("java.lang.String", "staticMethod", ImmutableList.of());
assertThat(staticMethod, isPresent());
assertEquals(minify, staticMethod.isRenamed());
- boolean publicizeCondition = isR8(shrinker) ? allowAccessModification
+ boolean publicizeCondition = shrinker.isR8() ? allowAccessModification
: minify && repackagePrefix != null && allowAccessModification;
assertEquals(publicizeCondition, staticMethod.getMethod().accessFlags.isPublic());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index fbf4e68..deb91d8 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.AsmTestBase;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -102,18 +103,18 @@
InternalOptions options = new InternalOptions();
AndroidApp app = readClassesAndAsmDump(CLASSES, ASM_CLASSES);
DexApplication application = new ApplicationReader(app, options, timing).read().toDirect();
- AppInfoWithSubtyping appInfoWithSubtyping = new AppInfoWithSubtyping(application);
+ AppView<? extends AppInfoWithSubtyping> appView =
+ new AppView<>(new AppInfoWithSubtyping(application), GraphLense.getIdentityLense());
ExecutorService executor = Executors.newSingleThreadExecutor();
- RootSet rootSet = new RootSetBuilder(appInfoWithSubtyping, application,
- buildKeepRuleForClass(Main.class, application.dexItemFactory), options).run(executor);
- appInfo =
- new Enqueuer(
- appInfoWithSubtyping,
- GraphLense.getIdentityLense(),
- options,
- options.forceProguardCompatibility)
- .traceApplication(rootSet, executor, timing);
+ RootSet rootSet =
+ new RootSetBuilder(
+ appView,
+ application,
+ buildKeepRuleForClass(Main.class, application.dexItemFactory),
+ options)
+ .run(executor);
+ appInfo = new Enqueuer(appView, options).traceApplication(rootSet, executor, timing);
// We do not run the tree pruner to ensure that the hierarchy is as designed and not modified
// due to liveness.
}
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java
new file mode 100644
index 0000000..b518683
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java
@@ -0,0 +1,140 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.shaking;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.debuginfo.DebugInfoInspector;
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes.TestKeepAttributes;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+
+public class KeepAttributesTest extends TestBase {
+
+ public static final Class CLASS = TestKeepAttributes.class;
+
+ @Test
+ public void keepAllAttributesInDebugMode()
+ throws ExecutionException, CompilationFailedException, IOException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }"
+ );
+ CodeInspector inspector = compile(keepRules, CompilationMode.DEBUG);
+ DebugInfoInspector debugInfo = debugInfoForMain(inspector);
+ checkLineNumbers(true, debugInfo);
+ checkLocals(true, debugInfo);
+ }
+
+ @Test
+ public void discardAllAttributes()
+ throws CompilationFailedException, IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }"
+ );
+ CodeInspector inspector = compile(keepRules, CompilationMode.RELEASE);
+ DebugInfoInspector debugInfo = debugInfoForMain(inspector);
+ checkLineNumbers(false, debugInfo);
+ checkLocals(false, debugInfo);
+ }
+
+ @Test
+ public void keepLineNumberTable()
+ throws CompilationFailedException, IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }",
+ "-keepattributes " + ProguardKeepAttributes.LINE_NUMBER_TABLE
+ );
+ CodeInspector inspector = compile(keepRules, CompilationMode.RELEASE);
+ DebugInfoInspector debugInfo = debugInfoForMain(inspector);
+ checkLineNumbers(true, debugInfo);
+ checkLocals(false, debugInfo);
+ }
+
+ @Test
+ public void keepLineNumberTableAndLocalVariableTable()
+ throws CompilationFailedException, IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }",
+ "-keepattributes "
+ + ProguardKeepAttributes.LINE_NUMBER_TABLE
+ + ", "
+ + ProguardKeepAttributes.LOCAL_VARIABLE_TABLE
+ );
+ CodeInspector inspector = compile(keepRules, CompilationMode.RELEASE);
+ DebugInfoInspector debugInfo = debugInfoForMain(inspector);
+ checkLineNumbers(true, debugInfo);
+ // Locals are never included in release builds.
+ checkLocals(false, debugInfo);
+ }
+
+ @Test
+ public void keepLocalVariableTable() throws IOException, ExecutionException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }",
+ "-keepattributes " + ProguardKeepAttributes.LOCAL_VARIABLE_TABLE
+ );
+ // Compiling with a keep rule for locals but no line results in an error in R8.
+ try {
+ compile(keepRules, CompilationMode.RELEASE);
+ } catch (CompilationFailedException e) {
+ assertTrue(e.getCause().getMessage().contains(ProguardKeepAttributes.LOCAL_VARIABLE_TABLE));
+ assertTrue(e.getCause().getMessage().contains(ProguardKeepAttributes.LINE_NUMBER_TABLE));
+ return;
+ }
+ fail("Expected error");
+ }
+
+ private CodeInspector compile(List<String> keepRules, CompilationMode mode)
+ throws CompilationFailedException, IOException, ExecutionException {
+ AndroidAppConsumers sink = new AndroidAppConsumers();
+ R8.run(
+ R8Command.builder()
+ .setMode(mode)
+ .addProgramFiles(
+ ToolHelper.getClassFilesForTestDirectory(
+ ToolHelper.getClassFileForTestClass(CLASS).getParent()))
+ .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
+ .addProguardConfiguration(keepRules, Origin.unknown())
+ .setProgramConsumer(sink.wrapProgramConsumer(emptyConsumer(Backend.DEX)))
+ .build());
+ AndroidApp app = sink.build();
+ CodeInspector codeInspector = new CodeInspector(app);
+ runOnArt(app, CLASS.getTypeName());
+ return codeInspector;
+ }
+
+ private DebugInfoInspector debugInfoForMain(CodeInspector inspector) {
+ return new DebugInfoInspector(
+ inspector,
+ CLASS.getTypeName(),
+ new MethodSignature("main", "void", Collections.singleton("java.lang.String[]")));
+ }
+
+ private void checkLineNumbers(boolean expected, DebugInfoInspector debugInfo) {
+ assertEquals("Expected " + (expected ? "line entries" : "no line entries"),
+ expected, debugInfo.getEntries().stream().anyMatch(e -> e.lineEntry));
+ }
+
+ private void checkLocals(boolean expected, DebugInfoInspector debugInfo) {
+ assertEquals("Expected " + (expected ? "locals" : "no locals"),
+ expected, debugInfo.getEntries().stream().anyMatch(e -> !e.locals.isEmpty()));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index f8907d6..1ee19bc 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.position.TextRange;
import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
import com.android.tools.r8.utils.AbortException;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.KeepingDiagnosticHandler;
@@ -208,8 +207,7 @@
public void parseNonJavaIdentifiers() throws Exception {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(dexItemFactory,
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(dexItemFactory, new Reporter());
String nonJavaIdentifiers =
String.join("\n", ImmutableList.of(
"-keep class -package-.-ClassNameWithDash-{",
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
index 7e4c4ef..9f9b797 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -33,7 +33,6 @@
import com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes.TestKeepAttributes;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -162,8 +161,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility && hasDefaultConstructor) {
@@ -283,8 +281,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
@@ -383,8 +380,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
@@ -489,8 +485,7 @@
// Check the Proguard compatibility rules generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
@@ -605,8 +600,7 @@
// Check the Proguard compatibility configuration generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
System.out.println(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
@@ -657,8 +651,7 @@
inspection.accept(new CodeInspector(app));
// Check the Proguard compatibility configuration generated.
ProguardConfigurationParser parser =
- new ProguardConfigurationParser(new DexItemFactory(),
- new Reporter(new DefaultDiagnosticsHandler()));
+ new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
parser.parse(proguardCompatibilityRules);
ProguardConfiguration configuration = parser.getConfigRawForTesting();
compatInspection.accept(configuration);
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
index 24986e1..cf14d8b 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
@@ -40,27 +40,35 @@
R8_COMPAT,
R8_COMPAT_CF,
R8,
- R8_CF
- }
+ R8_CF;
- protected static boolean isR8(Shrinker shrinker) {
- return shrinker == Shrinker.R8_COMPAT
- || shrinker == Shrinker.R8_COMPAT_CF
- || shrinker == Shrinker.R8
- || shrinker == Shrinker.R8_CF;
- }
+ public boolean isR8() {
+ return this == R8_COMPAT
+ || this == R8_COMPAT_CF
+ || this == R8
+ || this == R8_CF;
+ }
- protected static boolean generatesDex(Shrinker shrinker) {
- return shrinker == Shrinker.PROGUARD6_THEN_D8
- || shrinker == Shrinker.R8_COMPAT
- || shrinker == Shrinker.R8;
- }
+ public boolean generatesDex() {
+ return this == PROGUARD6_THEN_D8
+ || this == R8_COMPAT
+ || this == R8;
+ }
- protected static boolean generatesCf(Shrinker shrinker) {
- return shrinker == Shrinker.PROGUARD5
- || shrinker == Shrinker.PROGUARD6
- || shrinker == Shrinker.R8_COMPAT_CF
- || shrinker == Shrinker.R8_CF;
+ public boolean generatesCf() {
+ return this == PROGUARD5
+ || this == PROGUARD6
+ || this == R8_COMPAT_CF
+ || this == R8_CF;
+ }
+
+ public Backend toBackend() {
+ if (generatesDex()) {
+ return Backend.DEX;
+ }
+ assert generatesCf();
+ return Backend.CF;
+ }
}
protected AndroidApp runShrinker(
@@ -80,13 +88,13 @@
case PROGUARD6_THEN_D8:
return runProguard6AndD8(programClasses, proguardConfig, proguardMap);
case R8_COMPAT:
- return runR8Compat(programClasses, proguardConfig, Backend.DEX);
+ return runR8Compat(programClasses, proguardConfig, proguardMap, Backend.DEX);
case R8_COMPAT_CF:
- return runR8Compat(programClasses, proguardConfig, Backend.CF);
+ return runR8Compat(programClasses, proguardConfig, proguardMap, Backend.CF);
case R8:
- return runR8(programClasses, proguardConfig, Backend.DEX);
+ return runR8(programClasses, proguardConfig, proguardMap, Backend.DEX);
case R8_CF:
- return runR8(programClasses, proguardConfig, Backend.CF);
+ return runR8(programClasses, proguardConfig, proguardMap, Backend.CF);
}
throw new IllegalArgumentException("Unknown shrinker: " + mode);
}
@@ -118,34 +126,45 @@
throw new IllegalArgumentException("Unknown shrinker: " + mode);
}
- protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
+ protected AndroidApp runR8(
+ List<Class> programClasses,
+ String proguardConfig,
+ Path proguardMap,
+ Backend backend)
throws Exception {
- return runR8(programClasses, proguardConfig, null, backend);
+ return runR8(programClasses, proguardConfig, proguardMap, null, backend);
}
protected AndroidApp runR8(
List<Class> programClasses,
String proguardConfig,
+ Path proguardMap,
Consumer<InternalOptions> configure,
Backend backend)
throws Exception {
AndroidApp app = readClassesAndRuntimeJar(programClasses, backend);
R8Command.Builder builder = ToolHelper.prepareR8CommandBuilder(app, emptyConsumer(backend));
ToolHelper.allowTestProguardOptions(builder);
- builder.addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown());
+ builder.addProguardConfiguration(
+ ImmutableList.of(proguardConfig, toPrintMappingRule(proguardMap)), Origin.unknown());
return ToolHelper.runR8(builder.build(), configure);
}
protected CodeInspector inspectR8Result(
List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
- return new CodeInspector(runR8(programClasses, proguardConfig, backend));
+ return new CodeInspector(runR8(programClasses, proguardConfig, null, backend));
}
protected AndroidApp runR8Compat(
- List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
+ List<Class> programClasses,
+ String proguardConfig,
+ Path proguardMap,
+ Backend backend)
+ throws Exception {
CompatProguardCommandBuilder builder = new CompatProguardCommandBuilder(true);
ToolHelper.allowTestProguardOptions(builder);
- builder.addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown());
+ builder.addProguardConfiguration(
+ ImmutableList.of(proguardConfig, toPrintMappingRule(proguardMap)), Origin.unknown());
programClasses.forEach(
clazz -> builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz)));
if (backend == Backend.DEX) {
@@ -161,7 +180,7 @@
protected CodeInspector inspectR8CompatResult(
List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
- return new CodeInspector(runR8Compat(programClasses, proguardConfig, backend));
+ return new CodeInspector(runR8Compat(programClasses, proguardConfig, null, backend));
}
protected AndroidApp runProguard5(
@@ -298,4 +317,8 @@
assertThat(c, not(isPresent()));
}
}
+
+ private String toPrintMappingRule(Path proguardMap) {
+ return proguardMap == null ? "" : "-printmapping " + proguardMap.toAbsolutePath();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
new file mode 100644
index 0000000..e20b80a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
@@ -0,0 +1,354 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.shaking.forceproguardcompatibility.defaultctor;
+
+import static com.android.tools.r8.shaking.forceproguardcompatibility.defaultctor.ExternalizableDataClass.TYPE_1;
+import static com.android.tools.r8.shaking.forceproguardcompatibility.defaultctor.ExternalizableDataClass.TYPE_2;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+final class ExternalizableDataClass implements Externalizable {
+ static final byte TYPE_1 = 1;
+ static final byte TYPE_2 = 2;
+
+ private byte byteField;
+ private Object objectField;
+
+ // Default constructor for deserialization
+ public ExternalizableDataClass() {
+ }
+
+ // Constructor for serialization
+ public ExternalizableDataClass(byte byteField, Object objectField) {
+ this.byteField = byteField;
+ this.objectField = objectField;
+ }
+
+ @Override
+ public void writeExternal(ObjectOutput objectOutput) throws IOException {
+ writeInternal(byteField, objectField, objectOutput);
+ }
+
+ private static void writeInternal(byte b, Object obj, DataOutput out) throws IOException {
+ out.writeByte(b);
+ switch (b) {
+ case TYPE_1:
+ ((Delegate1) obj).delegateWrite(out);
+ break;
+ case TYPE_2:
+ ((Delegate2) obj).delegateWrite(out);
+ break;
+ default:
+ throw new InvalidClassException("Unknown type: " + b);
+ }
+ }
+
+ @Override
+ public void readExternal(ObjectInput objectInput) throws IOException {
+ byteField = objectInput.readByte();
+ objectField = readInternal(byteField, objectInput);
+ }
+
+ private static Object readInternal(byte type, DataInput in) throws IOException {
+ switch (type) {
+ case TYPE_1: return Delegate1.delegateRead(in);
+ case TYPE_2: return Delegate2.delegateRead(in);
+ default:
+ throw new InvalidClassException("Unknown type: " + type);
+ }
+ }
+
+ private Object readResolve() {
+ return objectField;
+ }
+
+ @Override
+ public String toString() {
+ return "{ type: " + byteField + ", obj: " + objectField.toString() + " }";
+ }
+}
+
+final class Delegate1 implements Serializable {
+ private int intField;
+
+ private Object writeReplace() {
+ return new ExternalizableDataClass(TYPE_1, this);
+ }
+
+ static Delegate1 of(int intField) {
+ Delegate1 instance = new Delegate1();
+ instance.intField = intField;
+ return instance;
+ }
+
+ void delegateWrite(DataOutput out) throws IOException {
+ out.writeInt(intField);
+ }
+
+ static Object delegateRead(DataInput in) throws IOException {
+ int i = in.readInt();
+ return Delegate1.of(i);
+ }
+
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ @Override
+ public String toString() {
+ return "(" + intField + ")";
+ }
+}
+
+final class Delegate2 implements Serializable {
+ private String stringField;
+
+ private Object writeReplace() {
+ return new ExternalizableDataClass(TYPE_2, this);
+ }
+
+ static Delegate2 of(String stringField) {
+ Delegate2 instance = new Delegate2();
+ instance.stringField = stringField;
+ return instance;
+ }
+
+ void delegateWrite(DataOutput out) throws IOException {
+ out.writeUTF(stringField);
+ }
+
+ static Object delegateRead(DataInput in) throws IOException {
+ String s = in.readUTF();
+ return Delegate2.of(s);
+ }
+
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ @Override
+ public String toString() {
+ return "<" + stringField + ">";
+ }
+}
+
+class ExternalizableTestMain {
+ public static void main(String[] args) throws Exception {
+ Delegate2 data2 = Delegate2.of("MessageToSerialize");
+ // "Before: <MessageToSerialize>"
+ System.out.println("Before: " + data2.toString());
+
+ // Serialization
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
+ objectOutputStream.writeObject(data2);
+ objectOutputStream.close();
+
+ byte[] byteArray = out.toByteArray();
+
+ // Deserialization
+ ByteArrayInputStream in = new ByteArrayInputStream(byteArray);
+ ObjectInputStream objectInputStream = new ObjectInputStream(in);
+ Object copy = objectInputStream.readObject();
+ assert copy instanceof Delegate2;
+ // "After: <MessageToSerialize>"
+ System.out.println("After: " + copy.toString());
+ }
+}
+
+class NonSerializableSuperClass {
+ protected String tag;
+
+ // Default constructor for deserialization
+ public NonSerializableSuperClass() {
+ this.tag = null;
+ }
+
+ public NonSerializableSuperClass(String tag) {
+ this.tag = tag;
+ }
+
+ @Override
+ public String toString() {
+ return tag == null ? "NULL" : tag;
+ }
+}
+
+class SerializableDataClass extends NonSerializableSuperClass implements Serializable {
+ private String extraTag;
+
+ public SerializableDataClass() {
+ super();
+ this.extraTag = null;
+ }
+
+ public SerializableDataClass(String tag, String extraTag) {
+ super(tag);
+ this.extraTag = extraTag;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ", " + (extraTag == null ? "NULL" : extraTag);
+ }
+}
+
+class SerializableTestMain {
+ public static void main(String[] args) throws Exception {
+ SerializableDataClass data = new SerializableDataClass("TagToSerialize", "ExtraToSerialize");
+ // "Before: TagToSerialize, ExtraToSerialize"
+ System.out.println("Before: " + data.toString());
+
+ // Serialization
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
+ objectOutputStream.writeObject(data);
+ objectOutputStream.close();
+
+ byte[] byteArray = out.toByteArray();
+
+ // Deserialization
+ ByteArrayInputStream in = new ByteArrayInputStream(byteArray);
+ ObjectInputStream objectInputStream = new ObjectInputStream(in);
+ Object copy = objectInputStream.readObject();
+ assert copy instanceof SerializableDataClass;
+ // "After: NULL, ExtraToSerialize"
+ System.out.println("After: " + copy.toString());
+ }
+}
+
+@RunWith(Parameterized.class)
+public class ExternalizableTest extends ProguardCompatibilityTestBase {
+ private final static List<Class> CLASSES_FOR_EXTERNALIZABLE = ImmutableList.of(
+ ExternalizableDataClass.class, Delegate1.class, Delegate2.class, ExternalizableTestMain.class
+ );
+
+ private final static List<Class> CLASSES_FOR_SERIALIZABLE = ImmutableList.of(
+ NonSerializableSuperClass.class, SerializableDataClass.class, SerializableTestMain.class
+ );
+
+ private final Shrinker shrinker;
+
+ @Parameterized.Parameters(name = "Shrinker: {0}")
+ public static Collection<Object> data() {
+ return ImmutableList.of(
+ Shrinker.PROGUARD6_THEN_D8, Shrinker.PROGUARD6,
+ Shrinker.R8_COMPAT, Shrinker.R8_COMPAT_CF,
+ Shrinker.R8, Shrinker.R8_CF);
+ }
+
+ public ExternalizableTest(Shrinker shrinker) {
+ this.shrinker = shrinker;
+ }
+
+ @Test
+ public void testExternalizable() throws Exception {
+ String javaOutput = runOnJava(ExternalizableTestMain.class);
+
+ List<String> config = ImmutableList.of(
+ keepMainProguardConfiguration(ExternalizableTestMain.class),
+ // https://www.guardsquare.com/en/products/proguard/manual/examples#serializable
+ "-keepclassmembers class * implements java.io.Serializable {",
+ //" private static final java.io.ObjectStreamField[] serialPersistentFields;",
+ " private void writeObject(java.io.ObjectOutputStream);",
+ " private void readObject(java.io.ObjectInputStream);",
+ " java.lang.Object writeReplace();",
+ " java.lang.Object readResolve();",
+ "}");
+
+ AndroidApp processedApp = runShrinker(shrinker, CLASSES_FOR_EXTERNALIZABLE, config);
+
+ // TODO(b/117302947): Need to update ART binary.
+ if (shrinker.generatesCf()) {
+ String output = runOnVM(
+ processedApp, ExternalizableTestMain.class.getCanonicalName(), shrinker.toBackend());
+ assertEquals(javaOutput.trim(), output.trim());
+ }
+
+ // https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serial-arch.html
+ // 1.11 The Externalizable Interface
+ // ...
+ // The class of an Externalizable object must do the following:
+ // ...
+ // * Have a public no-arg constructor
+ CodeInspector codeInspector = new CodeInspector(processedApp, proguardMap);
+ ClassSubject classSubject = codeInspector.clazz(ExternalizableDataClass.class);
+ assertThat(classSubject, isPresent());
+ MethodSubject init = classSubject.init(ImmutableList.of());
+ assertThat(init, isPresent());
+ }
+
+ @Test
+ public void testSerializable() throws Exception {
+ // TODO(b/116735204): R8 should keep default ctor() of first non-serializable superclass of
+ // serializable class.
+ if (shrinker.isR8()) {
+ return;
+ }
+
+ String javaOutput = runOnJava(SerializableTestMain.class);
+
+ List<String> config = ImmutableList.of(
+ keepMainProguardConfiguration(SerializableTestMain.class),
+ // https://www.guardsquare.com/en/products/proguard/manual/examples#serializable
+ "-keepclassmembers class * implements java.io.Serializable {",
+ //" private static final java.io.ObjectStreamField[] serialPersistentFields;",
+ " private void writeObject(java.io.ObjectOutputStream);",
+ " private void readObject(java.io.ObjectInputStream);",
+ " java.lang.Object writeReplace();",
+ " java.lang.Object readResolve();",
+ "}");
+
+ AndroidApp processedApp = runShrinker(shrinker, CLASSES_FOR_SERIALIZABLE, config);
+ // TODO(b/117302947): Need to update ART binary.
+ if (shrinker.generatesCf()) {
+ String output = runOnVM(
+ processedApp, SerializableTestMain.class.getCanonicalName(), shrinker.toBackend());
+ assertEquals(javaOutput.trim(), output.trim());
+ }
+
+ // https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serial-arch.html
+ // 1.10 The Serializable Interface
+ // ...
+ // A Serializable class must do the following:
+ // ...
+ // * Have access to the no-arg constructor of its first non-serializable superclass
+ CodeInspector codeInspector = new CodeInspector(processedApp, proguardMap);
+ ClassSubject classSubject = codeInspector.clazz(NonSerializableSuperClass.class);
+ assertThat(classSubject, isPresent());
+ MethodSubject init = classSubject.init(ImmutableList.of());
+ assertThat(init, isPresent());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
index e6de7cc..89d5079 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
@@ -45,10 +46,12 @@
}
@Override
- protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
+ protected AndroidApp runR8(
+ List<Class> programClasses, String proguardConfig, Path proguardMap, Backend backend)
throws Exception {
// Disable inlining, otherwise classes can be pruned away if all their methods are inlined.
- return runR8(programClasses, proguardConfig, o -> o.enableInlining = false, backend);
+ return runR8(
+ programClasses, proguardConfig, proguardMap, o -> o.enableInlining = false, backend);
}
@Test
@@ -104,8 +107,8 @@
assertTrue(methodSubject.getMethod().accessFlags.isPublic());
classSubject = codeInspector.clazz(ClassForSubsequent.class);
- if (isR8(shrinker)) {
- // TODO(b/72109068): ClassForIf#nonPublicMethod becomes public, and -if rule is not applied
+ if (shrinker.isR8()) {
+ // TODO(b/117330692): ClassForIf#nonPublicMethod becomes public, and -if rule is not applied
// at the 2nd tree shaking.
assertThat(classSubject, not(isPresent()));
return;
@@ -143,8 +146,8 @@
assertTrue(methodSubject.getMethod().accessFlags.isPublic());
classSubject = codeInspector.clazz(ClassForSubsequent.class);
- if (isR8(shrinker)) {
- // TODO(b/72109068): ClassForIf#nonPublicMethod becomes public, and -if rule is not applied
+ if (shrinker.isR8()) {
+ // TODO(b/117330692): ClassForIf#nonPublicMethod becomes public, and -if rule is not applied
// at the 2nd tree shaking.
assertThat(classSubject, not(isPresent()));
return;
@@ -219,8 +222,8 @@
assertThat(methodSubject, not(isPresent()));
methodSubject = classSubject.method(nonPublicMethod);
assertThat(methodSubject, isPresent());
- if (isR8(shrinker)) {
- // TODO(b/72109068): if kept in the 1st tree shaking, should not be publicized.
+ if (shrinker.isR8()) {
+ // TODO(b/117330692): if kept in the 1st tree shaking, should not be publicized.
assertTrue(methodSubject.getMethod().accessFlags.isPublic());
return;
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
index b003b7b..165a68f 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
@@ -89,9 +89,10 @@
}
@Override
- protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
+ protected AndroidApp runR8(
+ List<Class> programClasses, String proguardConfig, Path proguardMap, Backend backend)
throws Exception {
- return super.runR8(programClasses, proguardConfig, this::configure, backend);
+ return super.runR8(programClasses, proguardConfig, proguardMap, this::configure, backend);
}
private void check(AndroidApp app) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
index 1a74018..1f06e72 100644
--- a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
@@ -33,7 +33,7 @@
String expected = String.join(System.lineSeparator(), ImmutableList.of(
"com.android.tools.r8.shaking.whyareyoukeeping.A",
"|- is live because referenced in keep rule:",
- "| -keep class com.android.tools.r8.shaking.whyareyoukeeping.A {",
+ "| -keep class com.android.tools.r8.shaking.whyareyoukeeping.A {",
"| *;",
"| };",
""));
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index 3203f9c..dedb839 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -24,6 +24,8 @@
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfThrow;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.code.ValueType;
import org.objectweb.asm.Opcodes;
@@ -40,6 +42,41 @@
}
@Override
+ public boolean isInstancePut() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTFIELD;
+ }
+
+ @Override
+ public boolean isStaticPut() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTSTATIC;
+ }
+
+ @Override
+ public boolean isInstanceGet() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETFIELD;
+ }
+
+ @Override
+ public boolean isStaticGet() {
+ return instruction instanceof CfFieldInstruction
+ && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETSTATIC;
+ }
+
+ @Override
+ public DexField getField() {
+ assert isFieldAccess();
+ return ((CfFieldInstruction) instruction).getField();
+ }
+
+ @Override
+ public boolean isInvoke() {
+ return instruction instanceof CfInvoke || instruction instanceof CfInvokeDynamic;
+ }
+
+ @Override
public boolean isInvokeVirtual() {
return instruction instanceof CfInvoke
&& ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKEVIRTUAL;
@@ -58,6 +95,12 @@
}
@Override
+ public DexMethod getMethod() {
+ assert isInvoke();
+ return ((CfInvoke) instruction).getMethod();
+ }
+
+ @Override
public boolean isNop() {
return instruction instanceof CfNop;
}
@@ -105,40 +148,11 @@
}
@Override
- public boolean isInvoke() {
- return instruction instanceof CfInvoke || instruction instanceof CfInvokeDynamic;
- }
-
- @Override
public boolean isNewInstance() {
return instruction instanceof CfNew;
}
@Override
- public boolean isInstancePut() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTFIELD;
- }
-
- @Override
- public boolean isStaticPut() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTSTATIC;
- }
-
- @Override
- public boolean isInstanceGet() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETFIELD;
- }
-
- @Override
- public boolean isStaticGet() {
- return instruction instanceof CfFieldInstruction
- && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETSTATIC;
- }
-
- @Override
public boolean isCheckCast() {
return instruction instanceof CfCheckCast;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
index 4ea699a..e1d74c1 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
@@ -67,6 +67,8 @@
import com.android.tools.r8.code.SputShort;
import com.android.tools.r8.code.SputWide;
import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
public class DexInstructionSubject implements InstructionSubject {
protected final Instruction instruction;
@@ -81,6 +83,65 @@
}
@Override
+ public boolean isInstanceGet() {
+ return instruction instanceof Iget
+ || instruction instanceof IgetBoolean
+ || instruction instanceof IgetByte
+ || instruction instanceof IgetShort
+ || instruction instanceof IgetChar
+ || instruction instanceof IgetWide
+ || instruction instanceof IgetObject;
+ }
+
+ @Override
+ public boolean isInstancePut() {
+ return instruction instanceof Iput
+ || instruction instanceof IputBoolean
+ || instruction instanceof IputByte
+ || instruction instanceof IputShort
+ || instruction instanceof IputChar
+ || instruction instanceof IputWide
+ || instruction instanceof IputObject;
+ }
+
+ @Override
+ public boolean isStaticGet() {
+ return instruction instanceof Sget
+ || instruction instanceof SgetBoolean
+ || instruction instanceof SgetByte
+ || instruction instanceof SgetShort
+ || instruction instanceof SgetChar
+ || instruction instanceof SgetWide
+ || instruction instanceof SgetObject;
+ }
+
+ @Override
+ public boolean isStaticPut() {
+ return instruction instanceof Sput
+ || instruction instanceof SputBoolean
+ || instruction instanceof SputByte
+ || instruction instanceof SputShort
+ || instruction instanceof SputChar
+ || instruction instanceof SputWide
+ || instruction instanceof SputObject;
+ }
+
+ @Override
+ public DexField getField() {
+ assert isFieldAccess();
+ return instruction.getField();
+ }
+
+ @Override
+ public boolean isInvoke() {
+ return isInvokeVirtual()
+ || isInvokeInterface()
+ || isInvokeDirect()
+ || isInvokeSuper()
+ || isInvokeStatic();
+ }
+
+ @Override
public boolean isInvokeVirtual() {
return instruction instanceof InvokeVirtual || instruction instanceof InvokeVirtualRange;
}
@@ -95,6 +156,20 @@
return instruction instanceof InvokeStatic || instruction instanceof InvokeStaticRange;
}
+ public boolean isInvokeSuper() {
+ return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
+ }
+
+ public boolean isInvokeDirect() {
+ return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
+ }
+
+ @Override
+ public DexMethod getMethod() {
+ assert isInvoke();
+ return instruction.getMethod();
+ }
+
@Override
public boolean isNop() {
return instruction instanceof Nop;
@@ -147,15 +222,6 @@
}
@Override
- public boolean isInvoke() {
- return isInvokeVirtual()
- || isInvokeInterface()
- || isInvokeDirect()
- || isInvokeSuper()
- || isInvokeStatic();
- }
-
- @Override
public boolean isNewInstance() {
return instruction instanceof NewInstance;
}
@@ -170,63 +236,11 @@
return isCheckCast() && ((CheckCast) instruction).getType().toString().equals(type);
}
- public boolean isInvokeSuper() {
- return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
- }
-
- public boolean isInvokeDirect() {
- return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
- }
-
public boolean isConst4() {
return instruction instanceof Const4;
}
@Override
- public boolean isInstanceGet() {
- return instruction instanceof Iget
- || instruction instanceof IgetBoolean
- || instruction instanceof IgetByte
- || instruction instanceof IgetShort
- || instruction instanceof IgetChar
- || instruction instanceof IgetWide
- || instruction instanceof IgetObject;
- }
-
- @Override
- public boolean isInstancePut() {
- return instruction instanceof Iput
- || instruction instanceof IputBoolean
- || instruction instanceof IputByte
- || instruction instanceof IputShort
- || instruction instanceof IputChar
- || instruction instanceof IputWide
- || instruction instanceof IputObject;
- }
-
- @Override
- public boolean isStaticGet() {
- return instruction instanceof Sget
- || instruction instanceof SgetBoolean
- || instruction instanceof SgetByte
- || instruction instanceof SgetShort
- || instruction instanceof SgetChar
- || instruction instanceof SgetWide
- || instruction instanceof SgetObject;
- }
-
- @Override
- public boolean isStaticPut() {
- return instruction instanceof Sput
- || instruction instanceof SputBoolean
- || instruction instanceof SputByte
- || instruction instanceof SputShort
- || instruction instanceof SputChar
- || instruction instanceof SputWide
- || instruction instanceof SputObject;
- }
-
- @Override
public boolean isIf() {
return instruction instanceof IfEq
|| instruction instanceof IfEqz
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index e7eaa60..fb0e0d3 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.utils.codeinspector;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+
public interface InstructionSubject {
enum JumboStringMode {
@@ -13,12 +16,26 @@
boolean isFieldAccess();
+ boolean isInstancePut();
+
+ boolean isStaticPut();
+
+ boolean isInstanceGet();
+
+ boolean isStaticGet();
+
+ DexField getField();
+
+ boolean isInvoke();
+
boolean isInvokeVirtual();
boolean isInvokeInterface();
boolean isInvokeStatic();
+ DexMethod getMethod();
+
boolean isNop();
boolean isConstString(JumboStringMode jumboStringMode);
@@ -37,18 +54,8 @@
boolean isThrow();
- boolean isInvoke();
-
boolean isNewInstance();
- boolean isInstancePut();
-
- boolean isStaticPut();
-
- boolean isInstanceGet();
-
- boolean isStaticGet();
-
boolean isCheckCast();
boolean isCheckCast(String type);
diff --git a/tools/build_r8lib.py b/tools/build_r8lib.py
index 4b7473e..5af6d4d 100755
--- a/tools/build_r8lib.py
+++ b/tools/build_r8lib.py
@@ -9,6 +9,7 @@
'''
import argparse
+import gradle
import os
import subprocess
import toolhelper
@@ -16,39 +17,70 @@
parser = argparse.ArgumentParser(description=__doc__.strip(),
formatter_class=argparse.RawTextHelpFormatter)
-
-SAMPLE_JAR = os.path.join(utils.REPO_ROOT, 'tests/d8_api_usage_sample.jar')
-R8LIB_JAR = os.path.join(utils.LIBS, 'r8lib.jar')
-R8LIB_MAP_FILE = os.path.join(utils.LIBS, 'r8lib-map.txt')
+parser.add_argument('-e', '--exclude_deps', action='store_true',
+ help='Create lib jar without dependencies')
+parser.add_argument('-k', '--keep', default=utils.R8LIB_KEEP_RULES,
+ help='Keep rules file for lib')
+parser.add_argument('-n', '--no_relocate', action='store_true',
+ help='Create lib jar without relocating libraries')
+parser.add_argument('-o', '--out', default=None,
+ help='Output for built library')
+parser.add_argument('-t', '--target', default='r8',
+ help='Compile target for library')
API_LEVEL = 26
-ANDROID_JAR = 'third_party/android_jar/lib-v%s/android.jar' % API_LEVEL
+DEPS_JAR = os.path.join(utils.LIBS, 'deps.jar')
+SAMPLE_JAR = os.path.join(utils.REPO_ROOT, 'tests', 'd8_api_usage_sample.jar')
-
-def build_r8lib(output_path=None, output_map=None, **kwargs):
+def build_r8lib(target, exclude_deps, no_relocate, keep_rules_path,
+ output_path, **kwargs):
+ # Clean the build directory to ensure no repackaging of any existing
+ # lib or deps.
+ gradle.RunGradle(['clean'])
+ lib_args = [target]
+ deps_args = ['repackageDeps']
+ if exclude_deps:
+ lib_args.append('-Pexclude_deps')
+ if no_relocate:
+ lib_args.append('-Plib_no_relocate')
+ deps_args.append('-Plib_no_relocate')
+ # Produce the r8lib target to be processed later.
+ gradle.RunGradle(lib_args)
+ target_lib = os.path.join(utils.LIBS, target + '.jar')
+ temp_lib = os.path.join(utils.LIBS, target + '_to_process.jar')
+ os.rename(target_lib, temp_lib)
+ # Produce the dependencies needed for running r8 on lib.jar.
+ gradle.RunGradle(deps_args)
+ temp_deps = os.path.join(utils.LIBS, target + 'lib_deps.jar')
+ os.rename(DEPS_JAR, temp_deps)
+ # Produce R8 for compiling lib
if output_path is None:
- output_path = R8LIB_JAR
- if output_map is None:
- output_map = R8LIB_MAP_FILE
+ output_path = target + 'lib.jar'
+ output_map_path = os.path.splitext(output_path)[0] + '.map'
toolhelper.run(
'r8',
('--release',
'--classfile',
'--lib', utils.RT_JAR,
- utils.R8_JAR,
+ '--lib', temp_deps,
+ temp_lib,
'--output', output_path,
- '--pg-conf', utils.R8LIB_KEEP_RULES,
- '--pg-map-output', output_map),
+ '--pg-conf', keep_rules_path,
+ '--pg-map-output', output_map_path),
**kwargs)
+ if exclude_deps:
+ return [output_path, temp_deps]
+ else:
+ return [output_path]
-def test_d8sample():
+def test_d8sample(paths):
with utils.TempDir() as path:
- args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, R8LIB_JAR),
+ args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, ":".join(paths)),
'com.android.tools.apiusagesample.D8ApiUsageSample',
'--output', path,
'--min-api', str(API_LEVEL),
- '--lib', ANDROID_JAR,
+ '--lib', utils.get_android_jar(API_LEVEL),
'--classpath', utils.R8_JAR,
'--main-dex-list', '/dev/null',
os.path.join(utils.BUILD, 'test/examples/hello.jar')]
@@ -56,30 +88,30 @@
subprocess.check_call(args)
-def test_r8command():
+def test_r8command(paths):
with utils.TempDir() as path:
- # SAMPLE_JAR and R8LIB_JAR should not have any classes in common, since e.g.
- # R8CommandParser should have been minified in R8LIB_JAR.
- # Just in case R8CommandParser is also present in R8LIB_JAR, we put
+ # SAMPLE_JAR and LIB_JAR should not have any classes in common, since e.g.
+ # R8CommandParser should have been minified in LIB_JAR.
+ # Just in case R8CommandParser is also present in LIB_JAR, we put
# SAMPLE_JAR first on the classpath to use its version of R8CommandParser.
- args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, R8LIB_JAR),
+ args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, ":".join(paths)),
'com.android.tools.r8.R8CommandParser',
'--output', path + "/output.zip",
'--min-api', str(API_LEVEL),
- '--lib', ANDROID_JAR,
+ '--lib', utils.get_android_jar(API_LEVEL),
'--main-dex-list', '/dev/null',
os.path.join(utils.BUILD, 'test/examples/hello.jar')]
utils.PrintCmd(args)
subprocess.check_call(args)
-def test_r8cfcommand():
+def test_r8cfcommand(paths):
with utils.TempDir() as path:
- # SAMPLE_JAR and R8LIB_JAR should not have any classes in common, since e.g.
- # R8CommandParser should have been minified in R8LIB_JAR.
- # Just in case R8CommandParser is also present in R8LIB_JAR, we put
+ # SAMPLE_JAR and LIB_JAR should not have any classes in common, since e.g.
+ # R8CommandParser should have been minified in LIB_JAR.
+ # Just in case R8CommandParser is also present in LIB_JAR, we put
# SAMPLE_JAR first on the classpath to use its version of R8CommandParser.
- args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, R8LIB_JAR),
+ args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, ":".join(paths)),
'com.android.tools.r8.R8CommandParser',
'--classfile',
'--output', path + "/output.jar",
@@ -91,12 +123,16 @@
def main():
# Handle --help
- parser.parse_args()
-
- build_r8lib()
- test_d8sample()
- test_r8command()
- test_r8cfcommand()
+ args = parser.parse_args()
+ output_paths = build_r8lib(
+ args.target, args.exclude_deps, args.no_relocate, args.keep, args.out)
+ if args.target == 'r8':
+ gradle.RunGradle(['buildExampleJars'])
+ test_r8command(output_paths)
+ test_r8cfcommand(output_paths)
+ if args.target == 'd8':
+ gradle.RunGradle(['buildExampleJars'])
+ test_d8sample(output_paths)
if __name__ == '__main__':
diff --git a/tools/test.py b/tools/test.py
index 6c15ea5..b57d00f 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -23,32 +23,32 @@
def ParseOptions():
result = optparse.OptionParser()
- result.add_option('--no_internal',
+ result.add_option('--no-internal', '--no_internal',
help='Do not run Google internal tests.',
default=False, action='store_true')
- result.add_option('--archive_failures',
+ result.add_option('--archive-failures', '--archive_failures',
help='Upload test results to cloud storage on failure.',
default=False, action='store_true')
- result.add_option('--only_internal',
+ result.add_option('--only-internal', '--only_internal',
help='Only run Google internal tests.',
default=False, action='store_true')
- result.add_option('--all_tests',
+ result.add_option('--all-tests', '--all_tests',
help='Run tests in all configurations.',
default=False, action='store_true')
result.add_option('-v', '--verbose',
help='Print test stdout to, well, stdout.',
default=False, action='store_true')
- result.add_option('--dex_vm',
+ result.add_option('--dex-vm', '--dex_vm',
help='The android version of the vm to use. "all" will run the tests on '
'all art vm versions (stopping after first failed execution)',
default="default",
choices=ALL_ART_VMS + ["all"])
- result.add_option('--dex_vm_kind',
+ result.add_option('--dex-vm-kind', '--dex_vm_kind',
help='Whether to use host or target version of runtime',
default="host",
nargs=1,
choices=["host", "target"])
- result.add_option('--one_line_per_test',
+ result.add_option('--one-line-per-test', '--one_line_per_test',
help='Print a line before a tests starts and after it ends to stdout.',
default=False, action='store_true')
result.add_option('--tool',
@@ -58,32 +58,32 @@
result.add_option('--jctf',
help='Run JCTF tests with: "r8" (default) or "d8".',
default=False, action='store_true')
- result.add_option('--only_jctf',
+ result.add_option('--only-jctf', '--only_jctf',
help='Run only JCTF tests with: "r8" (default) or "d8".',
default=False, action='store_true')
- result.add_option('--jctf_compile_only',
+ result.add_option('--jctf-compile-only', '--jctf_compile_only',
help="Don't run, only compile JCTF tests.",
default=False, action='store_true')
- result.add_option('--aosp_jar',
+ result.add_option('--aosp-jar', '--aosp_jar',
help='Run aosp_jar test.',
default=False, action='store_true')
- result.add_option('--disable_assertions',
+ result.add_option('--disable-assertions', '--disable_assertions',
help='Disable assertions when running tests.',
default=False, action='store_true')
- result.add_option('--with_code_coverage',
+ result.add_option('--with-code-coverage', '--with_code_coverage',
help='Enable code coverage with Jacoco.',
default=False, action='store_true')
- result.add_option('--test_dir',
+ result.add_option('--test-dir', '--test_dir',
help='Use a custom directory for the test artifacts instead of a'
' temporary (which is automatically removed after the test).'
' Note that the directory will not be cleared before the test.')
- result.add_option('--java_home',
+ result.add_option('--java-home', '--java_home',
help='Use a custom java version to run tests.')
- result.add_option('--generate_golden_files_to',
+ result.add_option('--generate-golden-files-to', '--generate_golden_files_to',
help='Store dex files produced by tests in the specified directory.'
' It is aimed to be read on platforms with no host runtime available'
' for comparison.')
- result.add_option('--use_golden_files_in',
+ result.add_option('--use-golden-files-in', '--use_golden_files_in',
help='Download golden files hierarchy for this commit in the specified'
' location and use them instead of executing on host runtime.')