Merge "Ignore annotations for non-existent parameters"
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 7bed8ae..2f40a77 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -256,7 +256,7 @@
String proguardSeedsData = null;
timing.begin("Strip unused code");
try {
- Set<DexType> missingClasses = appView.getAppInfo().getMissingClasses();
+ Set<DexType> missingClasses = appView.appInfo().getMissingClasses();
missingClasses = filterMissingClasses(
missingClasses, options.proguardConfiguration.getDontWarnPatterns());
if (!missingClasses.isEmpty()) {
@@ -273,14 +273,14 @@
// Compute kotlin info before setting the roots and before
// kotlin metadata annotation is removed.
- computeKotlinInfoForProgramClasses(application, appView.getAppInfo());
+ computeKotlinInfoForProgramClasses(application, appView.appInfo());
final ProguardConfiguration.Builder compatibility =
ProguardConfiguration.builder(application.dexItemFactory, options.reporter);
rootSet =
new RootSetBuilder(
- appView.getAppInfo(),
+ appView.appInfo(),
application,
options.proguardConfiguration.getRules(),
options)
@@ -288,8 +288,8 @@
Enqueuer enqueuer =
new Enqueuer(
- appView.getAppInfo(),
- appView.getGraphLense(),
+ appView.appInfo(),
+ appView.graphLense(),
options,
options.forceProguardCompatibility,
compatibility);
@@ -297,23 +297,23 @@
if (options.proguardConfiguration.isPrintSeeds()) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bytes);
- RootSetBuilder.writeSeeds(appView.getAppInfo().withLiveness(), out, type -> true);
+ RootSetBuilder.writeSeeds(appView.appInfo().withLiveness(), out, type -> true);
out.flush();
proguardSeedsData = bytes.toString();
}
if (options.enableTreeShaking) {
TreePruner pruner =
- new TreePruner(application, appView.getAppInfo().withLiveness(), options);
+ new TreePruner(application, appView.appInfo().withLiveness(), options);
application = pruner.run();
// Recompute the subtyping information.
appView.setAppInfo(
appView
- .getAppInfo()
+ .appInfo()
.withLiveness()
.prunedCopyFrom(application, pruner.getRemovedClasses()));
- new AbstractMethodRemover(appView.getAppInfo()).run();
+ new AbstractMethodRemover(appView.appInfo()).run();
}
- new AnnotationRemover(appView.getAppInfo().withLiveness(), compatibility, options).run();
+ new AnnotationRemover(appView.appInfo().withLiveness(), compatibility, options).run();
// TODO(69445518): This is still work in progress, and this file writing is currently used
// for testing.
@@ -341,10 +341,10 @@
// We can now remove visibility bridges. Note that we do not need to update the
// invoke-targets here, as the existing invokes will simply dispatch to the now
// visible super-method. MemberRebinding, if run, will then dispatch it correctly.
- application = new VisibilityBridgeRemover(appView.getAppInfo(), application).run();
+ application = new VisibilityBridgeRemover(appView.appInfo(), application).run();
}
- if (appView.getAppInfo().hasLiveness()) {
+ if (appView.appInfo().hasLiveness()) {
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
if (options.proguardConfiguration.hasApplyMappingFile()) {
@@ -353,28 +353,29 @@
timing.begin("apply-mapping");
appView.setGraphLense(
new ProguardMapApplier(appView.withLiveness(), seedMapper).run(timing));
- application = application.asDirect().rewrittenWithLense(appView.getGraphLense());
+ application = application.asDirect().rewrittenWithLense(appView.graphLense());
appView.setAppInfo(
appView
- .getAppInfo()
+ .appInfo()
.withLiveness()
- .rewrittenWithLense(application.asDirect(), appView.getGraphLense()));
+ .rewrittenWithLense(application.asDirect(), appView.graphLense()));
timing.end();
}
appView.setGraphLense(new MemberRebindingAnalysis(appViewWithLiveness).run());
if (options.enableVerticalClassMerging) {
timing.begin("ClassMerger");
- VerticalClassMerger classMerger =
+ VerticalClassMerger verticalClassMerger =
new VerticalClassMerger(
application, appViewWithLiveness, executorService, options, timing);
- appView.setGraphLense(classMerger.run());
+ appView.setGraphLense(verticalClassMerger.run());
+ appView.setVerticallyMergedClasses(verticalClassMerger.getMergedClasses());
timing.end();
- application = application.asDirect().rewrittenWithLense(appView.getGraphLense());
+ application = application.asDirect().rewrittenWithLense(appView.graphLense());
appViewWithLiveness.setAppInfo(
appViewWithLiveness
- .getAppInfo()
- .prunedCopyFrom(application, classMerger.getRemovedClasses())
- .rewrittenWithLense(application.asDirect(), appView.getGraphLense()));
+ .appInfo()
+ .prunedCopyFrom(application, verticalClassMerger.getRemovedClasses())
+ .rewrittenWithLense(application.asDirect(), appView.graphLense()));
}
// Collect switch maps and ordinals maps.
appViewWithLiveness.setAppInfo(new SwitchMapCollector(appViewWithLiveness, options).run());
@@ -389,11 +390,8 @@
Set<DexCallSite> desugaredCallSites;
CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
try {
- IRConverter converter =
- new IRConverter(
- appView.getAppInfo(), options, timing, printer, appView.getGraphLense());
+ IRConverter converter = new IRConverter(appView, options, timing, printer);
application = converter.optimize(application, executorService);
- appView.setGraphLense(converter.getGraphLense());
desugaredCallSites = converter.getDesugaredCallSites();
} finally {
timing.end();
@@ -413,16 +411,15 @@
// Overwrite SourceFile if specified. This step should be done after IR conversion.
timing.begin("Rename SourceFile");
- new SourceFileRewriter(appView.getAppInfo(), options).run();
+ new SourceFileRewriter(appView.appInfo(), options).run();
timing.end();
if (!options.mainDexKeepRules.isEmpty()) {
appView.setAppInfo(new AppInfoWithSubtyping(application));
- Enqueuer enqueuer =
- new Enqueuer(appView.getAppInfo(), appView.getGraphLense(), options, true);
+ Enqueuer enqueuer = new Enqueuer(appView.appInfo(), appView.graphLense(), options, true);
// Lets find classes which may have code executed before secondary dex files installation.
RootSet mainDexRootSet =
- new RootSetBuilder(appView.getAppInfo(), application, options.mainDexKeepRules, options)
+ new RootSetBuilder(appView.appInfo(), application, options.mainDexKeepRules, options)
.run(executorService);
AppInfoWithLiveness mainDexAppInfo =
enqueuer.traceMainDex(mainDexRootSet, executorService, timing);
@@ -444,20 +441,19 @@
try {
Enqueuer enqueuer =
new Enqueuer(
- appView.getAppInfo(),
- appView.getGraphLense(),
+ appView.appInfo(),
+ appView.graphLense(),
options,
options.forceProguardCompatibility);
appView.setAppInfo(enqueuer.traceApplication(rootSet, executorService, timing));
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
if (options.enableTreeShaking) {
- TreePruner pruner =
- new TreePruner(application, appViewWithLiveness.getAppInfo(), options);
+ TreePruner pruner = new TreePruner(application, appViewWithLiveness.appInfo(), options);
application = pruner.run();
appViewWithLiveness.setAppInfo(
appViewWithLiveness
- .getAppInfo()
+ .appInfo()
.prunedCopyFrom(application, pruner.getRemovedClasses()));
// Print reasons on the application after pruning, so that we reflect the actual result.
ReasonPrinter reasonPrinter = enqueuer.getReasonPrinter(rootSet.reasonAsked);
@@ -478,8 +474,7 @@
// will happen. Just avoid the overhead.
NamingLens namingLens =
options.enableMinification
- ? new Minifier(
- appView.getAppInfo().withLiveness(), rootSet, desugaredCallSites, options)
+ ? new Minifier(appView.appInfo().withLiveness(), rootSet, desugaredCallSites, options)
.run(timing)
: NamingLens.getIdentityLens();
timing.end();
@@ -491,7 +486,7 @@
ClassNameMapper classNameMapper =
LineNumberOptimizer.run(
application,
- appView.getGraphLense(),
+ appView.graphLense(),
namingLens,
options.lineNumberOptimization == LineNumberOptimization.IDENTITY_MAPPING);
timing.end();
@@ -514,7 +509,7 @@
executorService,
application,
application.deadCode,
- appView.getGraphLense(),
+ appView.graphLense(),
namingLens,
proguardSeedsData,
options,
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 87232d2..0d4e79d 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.3.22-dev";
+ public static final String LABEL = "1.4.0-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 64a4ce4..3e4d611 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -5,12 +5,14 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.VerticalClassMerger.VerticallyMergedClasses;
public class AppView<T extends AppInfo> {
private T appInfo;
private final DexItemFactory dexItemFactory;
private GraphLense graphLense;
+ private VerticallyMergedClasses verticallyMergedClasses;
public AppView(T appInfo, GraphLense graphLense) {
this.appInfo = appInfo;
@@ -18,7 +20,7 @@
this.graphLense = graphLense;
}
- public T getAppInfo() {
+ public T appInfo() {
return appInfo;
}
@@ -26,11 +28,11 @@
this.appInfo = appInfo;
}
- public DexItemFactory getDexItemFactory() {
+ public DexItemFactory dexItemFactory() {
return dexItemFactory;
}
- public GraphLense getGraphLense() {
+ public GraphLense graphLense() {
return graphLense;
}
@@ -38,6 +40,16 @@
this.graphLense = graphLense;
}
+ // Get the result of vertical class merging. Returns null if vertical class merging has not been
+ // run.
+ public VerticallyMergedClasses verticallyMergedClasses() {
+ return verticallyMergedClasses;
+ }
+
+ public void setVerticallyMergedClasses(VerticallyMergedClasses verticallyMergedClasses) {
+ this.verticallyMergedClasses = verticallyMergedClasses;
+ }
+
public AppView<AppInfoWithLiveness> withLiveness() {
return new AppViewWithLiveness();
}
@@ -49,8 +61,8 @@
}
@Override
- public AppInfoWithLiveness getAppInfo() {
- return AppView.this.getAppInfo().withLiveness();
+ public AppInfoWithLiveness appInfo() {
+ return AppView.this.appInfo().withLiveness();
}
@Override
@@ -61,13 +73,13 @@
}
@Override
- public DexItemFactory getDexItemFactory() {
- return AppView.this.dexItemFactory;
+ public DexItemFactory dexItemFactory() {
+ return AppView.this.dexItemFactory();
}
@Override
- public GraphLense getGraphLense() {
- return AppView.this.getGraphLense();
+ public GraphLense graphLense() {
+ return AppView.this.graphLense();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index f1c1700..68f4c95 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -86,7 +86,6 @@
public LazyCfCode(
DexMethod method, Origin origin, ReparseContext context, JarApplicationReader application) {
-
this.method = method;
this.origin = origin;
this.context = context;
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 08d7a07..fbbe2fd 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
@@ -154,15 +154,6 @@
}
@Override
- public void detach() {
- if (current == null) {
- throw new IllegalStateException();
- }
- listIterator.remove();
- current = null;
- }
-
- @Override
public void replaceCurrentInstruction(Instruction newInstruction) {
if (current == null) {
throw new IllegalStateException();
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 f2ecc89..b5a3b90 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
@@ -26,6 +26,12 @@
this.value = value;
}
+ public static ConstString copyOf(IRCode code, ConstString original) {
+ Value newValue =
+ new Value(code.valueNumberGenerator.next(), original.outType(), original.getLocalInfo());
+ return new ConstString(newValue, original.getValue());
+ }
+
public Value dest() {
return outValue;
}
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 6f62d21..8f1a004 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -74,10 +74,6 @@
return outValue.isNeverNull();
}
- public final void forceSetPosition(Position position) {
- this.position = position;
- }
-
public String getPositionAsString() {
return position == null ? "???" : position.toString();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index 5d5e77c..cde197c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -72,16 +72,6 @@
void removeOrReplaceByDebugLocalRead();
/**
- * Remove the current instruction (aka the {@link Instruction} returned by the previous call to
- * {@link #next}) without updating its def/use chains.
- * <p>
- * This is useful for instance when moving an instruction to another block that still dominates
- * all its uses. In order to do that you would detach the instruction from the original
- * block and add it to the new block.
- */
- void detach();
-
- /**
* Replace the current instruction (aka the {@link Instruction} returned by the previous call to
* {@link #next} with the passed in <code>newInstruction</code>.
*
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index 1ee2f6b..524de92 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.conversion;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -147,8 +148,7 @@
public static CallGraph build(
DexApplication application,
- AppInfoWithLiveness appInfo,
- GraphLense graphLense,
+ AppView<AppInfoWithLiveness> appView,
InternalOptions options,
Timing timing) {
CallGraph graph = new CallGraph(options);
@@ -157,7 +157,7 @@
for (DexClass clazz : classes) {
for (DexEncodedMethod method : clazz.allMethodsSorted()) {
Node node = graph.ensureMethodNode(method);
- InvokeExtractor extractor = new InvokeExtractor(appInfo, graphLense, node, graph);
+ InvokeExtractor extractor = new InvokeExtractor(appView, node, graph);
method.registerCodeReferences(extractor);
}
}
@@ -169,7 +169,7 @@
timing.end();
assert cycleEliminator.breakCycles() == 0; // This time the cycles should be gone.
- graph.fillCallSiteSets(appInfo);
+ graph.fillCallSiteSets(appView.appInfo());
return graph;
}
@@ -478,16 +478,15 @@
private static class InvokeExtractor extends UseRegistry {
- AppInfoWithLiveness appInfo;
- GraphLense graphLense;
- Node caller;
- CallGraph graph;
+ private final AppInfoWithLiveness appInfo;
+ private final GraphLense graphLense;
+ private final Node caller;
+ private final CallGraph graph;
- InvokeExtractor(AppInfoWithLiveness appInfo, GraphLense graphLense, Node caller,
- CallGraph graph) {
- super(appInfo.dexItemFactory);
- this.appInfo = appInfo;
- this.graphLense = graphLense;
+ InvokeExtractor(AppView<AppInfoWithLiveness> appView, Node caller, CallGraph graph) {
+ super(appView.dexItemFactory());
+ this.appInfo = appView.appInfo();
+ this.graphLense = appView.graphLense();
this.caller = caller;
this.graph = graph;
}
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 6890595..1881f79 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
@@ -9,6 +9,7 @@
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.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotation;
@@ -91,8 +92,10 @@
private static final int PEEPHOLE_OPTIMIZATION_PASSES = 2;
- private final Timing timing;
public final AppInfo appInfo;
+ public final AppView<? extends AppInfoWithSubtyping> appView;
+
+ private final Timing timing;
private final Outliner outliner;
private final StringConcatRewriter stringConcatRewriter;
private final LambdaRewriter lambdaRewriter;
@@ -103,7 +106,6 @@
private final ClassStaticizer classStaticizer;
private final InternalOptions options;
private final CfgPrinter printer;
- private GraphLense graphLense;
private final CodeRewriter codeRewriter;
private final MemberValuePropagation memberValuePropagation;
private final LensCodeRewriter lensCodeRewriter;
@@ -124,19 +126,20 @@
// the current class being optimized.
private ConcurrentHashMap<DexType, DexProgramClass> cachedClasses = new ConcurrentHashMap<>();
+ // The argument `appView` is only available when full program optimizations are allowed
+ // (i.e., when running R8).
private IRConverter(
AppInfo appInfo,
InternalOptions options,
Timing timing,
CfgPrinter printer,
- GraphLense graphLense,
- boolean enableWholeProgramOptimizations) {
+ AppView<? extends AppInfoWithSubtyping> appView) {
assert appInfo != null;
assert options != null;
assert options.programConsumer != null;
this.timing = timing != null ? timing : new Timing("internal");
this.appInfo = appInfo;
- this.graphLense = graphLense != null ? graphLense : GraphLense.getIdentityLense();
+ this.appView = appView;
this.options = options;
this.printer = printer;
this.codeRewriter = new CodeRewriter(this, libraryMethodsReturningReceiver(), options);
@@ -155,16 +158,16 @@
? new CovariantReturnTypeAnnotationTransformer(this, appInfo.dexItemFactory)
: null;
this.stringOptimizer = new StringOptimizer();
- this.enableWholeProgramOptimizations = enableWholeProgramOptimizations;
+ this.enableWholeProgramOptimizations = appView != null;
if (enableWholeProgramOptimizations) {
assert appInfo.hasLiveness();
this.nonNullTracker = new NonNullTracker();
- this.inliner = new Inliner(this, options);
+ this.inliner = new Inliner(appView.withLiveness(), this, options);
this.outliner = new Outliner(appInfo.withLiveness(), options, this);
this.memberValuePropagation =
options.enableValuePropagation ?
new MemberValuePropagation(appInfo.withLiveness()) : null;
- this.lensCodeRewriter = new LensCodeRewriter(graphLense, appInfo.withSubtyping());
+ this.lensCodeRewriter = new LensCodeRewriter(appView, options);
if (appInfo.hasLiveness()) {
if (!appInfo.withLiveness().identifierNameStrings.isEmpty() && options.enableMinification) {
this.identifierNameStringMarker =
@@ -196,13 +199,8 @@
? new ClassStaticizer(appInfo.withLiveness(), this) : null;
}
- public void setGraphLense(GraphLense graphLense) {
- assert graphLense != null;
- this.graphLense = graphLense;
- }
-
- public GraphLense getGraphLense() {
- return graphLense;
+ public GraphLense graphLense() {
+ return appView != null ? appView.graphLense() : GraphLense.getIdentityLense();
}
public Set<DexCallSite> getDesugaredCallSites() {
@@ -216,33 +214,26 @@
/**
* Create an IR converter for processing methods with full program optimization disabled.
*/
- public IRConverter(
- AppInfo appInfo,
- InternalOptions options) {
- this(appInfo, options, null, null, null, false);
+ public IRConverter(AppInfo appInfo, InternalOptions options) {
+ this(appInfo, options, null, null, null);
}
/**
* Create an IR converter for processing methods with full program optimization disabled.
*/
- public IRConverter(
- AppInfo appInfo,
- InternalOptions options,
- Timing timing,
- CfgPrinter printer) {
- this(appInfo, options, timing, printer, null, false);
+ public IRConverter(AppInfo appInfo, InternalOptions options, Timing timing, CfgPrinter printer) {
+ this(appInfo, options, timing, printer, null);
}
/**
* Create an IR converter for processing methods with full program optimization enabled.
*/
public IRConverter(
- AppInfoWithSubtyping appInfo,
+ AppView<AppInfoWithSubtyping> appView,
InternalOptions options,
Timing timing,
- CfgPrinter printer,
- GraphLense graphLense) {
- this(appInfo, options, timing, printer, graphLense, true);
+ CfgPrinter printer) {
+ this(appView.appInfo(), options, timing, printer, appView);
}
private boolean enableInterfaceMethodDesugaring() {
@@ -472,8 +463,7 @@
OptimizationFeedback directFeedback = new OptimizationFeedbackDirect();
{
timing.begin("Build call graph");
- CallGraph callGraph =
- CallGraph.build(application, appInfo.withLiveness(), graphLense, options, timing);
+ CallGraph callGraph = CallGraph.build(application, appView.withLiveness(), options, timing);
timing.end();
timing.begin("IR conversion phase 1");
BiConsumer<IRCode, DexEncodedMethod> outlineHandler =
@@ -545,6 +535,7 @@
private void forEachSelectedOutliningMethod(
ExecutorService executorService, BiConsumer<IRCode, DexEncodedMethod> consumer)
throws ExecutionException {
+ assert appView != null;
assert !options.skipIR;
Set<DexEncodedMethod> methods = outliner.getMethodsSelectedForOutlining();
List<Future<?>> futures = new ArrayList<>();
@@ -554,7 +545,8 @@
() -> {
IRCode code =
method.buildIR(
- appInfo, graphLense, options, appInfo.originFor(method.method.holder));
+ appInfo, appView.graphLense(), options,
+ appInfo.originFor(method.method.holder));
assert code != null;
assert !method.getCode().isOutlineCode();
// Instead of repeating all the optimizations of rewriteCode(), only run the
@@ -562,7 +554,7 @@
// StringBuilder/StringBuffer method invocations, and removeDeadCode() to remove
// unused out-values.
codeRewriter.rewriteMoveResult(code);
- DeadCodeRemover.removeDeadCode(code, codeRewriter, graphLense, options);
+ DeadCodeRemover.removeDeadCode(code, codeRewriter, appView.graphLense(), options);
consumer.accept(code, method);
return null;
}));
@@ -712,7 +704,7 @@
return;
}
IRCode code =
- method.buildIR(appInfo, graphLense, options, appInfo.originFor(method.method.holder));
+ method.buildIR(appInfo, graphLense(), options, appInfo.originFor(method.method.holder));
if (code == null) {
feedback.markProcessed(method, ConstraintWithTarget.NEVER);
return;
@@ -742,7 +734,7 @@
if (lensCodeRewriter != null) {
lensCodeRewriter.rewrite(code, method);
} else {
- assert graphLense.isIdentityLense();
+ assert graphLense().isIdentityLense();
}
}
@@ -774,8 +766,7 @@
// TODO(zerny): Should we support inlining in debug mode? b/62937285
assert !options.debug;
new TypeAnalysis(appInfo, method).widening(method, code);
- inliner.performInlining(
- method, code, isProcessedConcurrently, callSiteInformation);
+ inliner.performInlining(method, code, isProcessedConcurrently, callSiteInformation);
}
if (!options.debug) {
stringOptimizer.computeConstStringLength(code, appInfo.dexItemFactory);
@@ -813,7 +804,7 @@
// Dead code removal. Performed after simplifications to remove code that becomes dead
// as a result of those simplifications. The following optimizations could reveal more
// dead code which is removed right before register allocation in performRegisterAllocation.
- DeadCodeRemover.removeDeadCode(code, codeRewriter, graphLense, options);
+ DeadCodeRemover.removeDeadCode(code, codeRewriter, graphLense(), options);
assert code.isConsistentSSA();
if (options.enableDesugaring && enableTryWithResourcesDesugaring()) {
@@ -829,7 +820,7 @@
if (classInliner != null) {
// Class inliner should work before lambda merger, so if it inlines the
- // lambda, it is not get collected by merger.
+ // lambda, it does not get collected by merger.
assert options.enableInlining && inliner != null;
classInliner.processMethodCode(
appInfo.withLiveness(), codeRewriter, method, code, isProcessedConcurrently,
@@ -948,7 +939,7 @@
private void finalizeToCf(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
assert !method.getCode().isDexCode();
CfBuilder builder = new CfBuilder(method, code, options.itemFactory);
- CfCode result = builder.build(codeRewriter, graphLense, options, appInfo);
+ CfCode result = builder.build(codeRewriter, graphLense(), options, appInfo);
method.setCode(result);
markProcessed(method, code, feedback);
}
@@ -992,7 +983,7 @@
private RegisterAllocator performRegisterAllocation(IRCode code, DexEncodedMethod method) {
// Always perform dead code elimination before register allocation. The register allocator
// does not allow dead code (to make sure that we do not waste registers for unneeded values).
- DeadCodeRemover.removeDeadCode(code, codeRewriter, graphLense, options);
+ DeadCodeRemover.removeDeadCode(code, codeRewriter, graphLense(), options);
materializeInstructionBeforeLongOperationsWorkaround(code);
workaroundForwardingInitializerBug(code);
LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(code, options);
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 ef490f7..283c163 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
@@ -7,6 +7,7 @@
import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -34,6 +35,7 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.InvokeCustom;
+import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMultiNewArray;
import com.android.tools.r8.ir.code.InvokeNewArray;
@@ -42,6 +44,8 @@
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.shaking.VerticalClassMerger.VerticallyMergedClasses;
+import com.android.tools.r8.utils.InternalOptions;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
@@ -50,14 +54,19 @@
public class LensCodeRewriter {
- private final GraphLense graphLense;
private final AppInfoWithSubtyping appInfo;
+ private final GraphLense graphLense;
+ private final VerticallyMergedClasses verticallyMergedClasses;
+ private final InternalOptions options;
private final Map<DexProto, DexProto> protoFixupCache = new ConcurrentHashMap<>();
- public LensCodeRewriter(GraphLense graphLense, AppInfoWithSubtyping appInfo) {
- this.graphLense = graphLense;
- this.appInfo = appInfo;
+ public LensCodeRewriter(
+ AppView<? extends AppInfoWithSubtyping> appView, InternalOptions options) {
+ this.appInfo = appView.appInfo();
+ this.graphLense = appView.graphLense();
+ this.verticallyMergedClasses = appView.verticallyMergedClasses();
+ this.options = options;
}
private Value makeOutValue(Instruction insn, IRCode code) {
@@ -121,6 +130,9 @@
if (!invokedHolder.isClassType()) {
continue;
}
+ if (invoke.isInvokeDirect()) {
+ checkInvokeDirect(method.method, invoke.asInvokeDirect());
+ }
GraphLenseLookupResult lenseLookup =
graphLense.lookupMethod(invokedMethod, method, invoke.getType());
DexMethod actualTarget = lenseLookup.getMethod();
@@ -246,6 +258,49 @@
assert code.isConsistentSSA();
}
+ // If the given invoke is on the form "invoke-direct A.<init>, v0, ..." and the definition of
+ // value v0 is "new-instance v0, B", where B is a subtype of A (see the Art800 and B116282409
+ // tests), then fail with a compilation error if A has previously been merged into B.
+ //
+ // The motivation for this is that the vertical class merger cannot easily recognize the above
+ // code pattern, since it runs prior to IR construction. Therefore, we currently allow merging
+ // A and B although this will lead to invalid code, because this code pattern does generally
+ // not occur in practice (it leads to a verification error on the JVM, but not on Art).
+ private void checkInvokeDirect(DexMethod method, InvokeDirect invoke) {
+ if (verticallyMergedClasses == null) {
+ // No need to check the invocation.
+ return;
+ }
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+ if (invokedMethod.name != appInfo.dexItemFactory.constructorMethodName) {
+ // Not a constructor call.
+ return;
+ }
+ if (invoke.arguments().isEmpty()) {
+ // The new instance should always be passed to the constructor call, but continue gracefully.
+ return;
+ }
+ Value receiver = invoke.arguments().get(0);
+ if (!receiver.isPhi() && receiver.definition.isNewInstance()) {
+ NewInstance newInstance = receiver.definition.asNewInstance();
+ if (newInstance.clazz != invokedMethod.holder
+ && verticallyMergedClasses.hasBeenMergedIntoSubtype(invokedMethod.holder)) {
+ // Generated code will not work. Fail with a compilation error.
+ throw options.reporter.fatalError(
+ String.format(
+ "Unable to rewrite `invoke-direct %s.<init>(new %s, ...)` in method `%s` after "
+ + "type `%s` was merged into `%s`. Please add the following rule to your "
+ + "Proguard configuration file: `-keep,allowobfuscation class %s`.",
+ invokedMethod.holder.toSourceString(),
+ newInstance.clazz,
+ method.toSourceString(),
+ invokedMethod.holder,
+ verticallyMergedClasses.getTargetFor(invokedMethod.holder),
+ invokedMethod.holder.toSourceString()));
+ }
+ }
+ }
+
private List<DexValue> rewriteBootstrapArgs(
List<DexValue> bootstrapArgs, DexEncodedMethod method, MethodHandleUse use) {
List<DexValue> newBoostrapArgs = null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 045cf52..82e3bff 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -423,9 +423,12 @@
}
if (converter.enableWholeProgramOptimizations &&
(!processor.methodsWithMovedCode.isEmpty() || !processor.movedMethods.isEmpty())) {
- converter.setGraphLense(
- new InterfaceMethodDesugaringLense(processor.movedMethods,
- processor.methodsWithMovedCode, converter.getGraphLense(), factory));
+ converter.appView.setGraphLense(
+ new InterfaceMethodDesugaringLense(
+ processor.movedMethods,
+ processor.methodsWithMovedCode,
+ converter.appView.graphLense(),
+ factory));
}
return processor.syntheticClasses;
}
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 c87c849..ffca4d1 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
@@ -174,8 +174,8 @@
lambdaClass.target.ensureAccessibility();
}
if (converter.enableWholeProgramOptimizations && !methodMapping.isEmpty()) {
- converter.setGraphLense(
- new LambdaRewriterGraphLense(methodMapping, converter.getGraphLense(), factory));
+ converter.appView.setGraphLense(
+ new LambdaRewriterGraphLense(methodMapping, converter.appView.graphLense(), factory));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
index 7d6dd7b..e1e534e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
@@ -92,7 +92,7 @@
}
public static boolean isSynthesizedCloseResourceMethod(DexMethod method, IRConverter converter) {
- DexMethod original = converter.getGraphLense().getOriginalMethodSignature(method);
+ DexMethod original = converter.graphLense().getOriginalMethodSignature(method);
assert original != null;
// We consider all methods of *any* class with expected name and signature
// to be synthesized by java 9 compiler for try-with-resources, reasoning:
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 d11946c..3330f08 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
@@ -1865,12 +1865,21 @@
if (i == 0) {
// For the first block process all ConstNumber instructions
// as well as ConstString instructions having just one use.
- shortenLiveRangesInsideBlock(block, dominatorTreeMemoization, addConstantInBlock,
- insn -> (insn.isConstNumber() && insn.outValue().numberOfAllUsers() != 0)
- || (insn.isConstString() && insn.outValue().numberOfAllUsers() == 1));
+ shortenLiveRangesInsideBlock(
+ code,
+ block,
+ dominatorTreeMemoization,
+ addConstantInBlock,
+ insn ->
+ (insn.isConstNumber() && insn.outValue().numberOfAllUsers() != 0)
+ || (insn.isConstString() && insn.outValue().numberOfAllUsers() == 1));
} else {
// For all following blocks only process ConstString with just one use.
- shortenLiveRangesInsideBlock(block, dominatorTreeMemoization, addConstantInBlock,
+ shortenLiveRangesInsideBlock(
+ code,
+ block,
+ dominatorTreeMemoization,
+ addConstantInBlock,
insn -> insn.isConstString() && insn.outValue().numberOfAllUsers() == 1);
}
}
@@ -1920,14 +1929,20 @@
assert code.isConsistentSSA();
}
- private void shortenLiveRangesInsideBlock(BasicBlock block,
+ private void shortenLiveRangesInsideBlock(
+ IRCode code,
+ BasicBlock block,
Supplier<DominatorTree> dominatorTreeMemoization,
Map<BasicBlock, List<Instruction>> addConstantInBlock,
- Predicate<Instruction> selector) {
+ Predicate<ConstInstruction> selector) {
InstructionListIterator it = block.listIterator();
while (it.hasNext()) {
- Instruction instruction = it.next();
+ Instruction next = it.next();
+ if (!next.isConstInstruction()) {
+ continue;
+ }
+ ConstInstruction instruction = next.asConstInstruction();
if (!selector.test(instruction) || instruction.outValue().hasLocalInfo()) {
continue;
}
@@ -1973,12 +1988,14 @@
}
}
- // Move the const instruction as close to its uses as possible.
- it.detach();
-
List<Instruction> csts =
addConstantInBlock.computeIfAbsent(dominator, k -> new ArrayList<>());
- csts.add(instruction);
+
+ ConstInstruction copy = instruction.isConstNumber()
+ ? ConstNumber.copyOf(code, instruction.asConstNumber())
+ : ConstString.copyOf(code, instruction.asConstString());
+ instruction.outValue().replaceUsers(copy.outValue());
+ csts.add(copy);
}
}
@@ -1993,7 +2010,7 @@
|| (hasCatchHandlers && i.instructionTypeCanThrow())
|| (options.canHaveCmpIfFloatBug() && i.isCmp()));
Instruction next = insertAt.previous();
- instruction.forceSetPosition(next.getPosition());
+ instruction.setPosition(next.getPosition());
insertAt.add(instruction);
}
@@ -2136,14 +2153,16 @@
for (ConstInstruction value : values) {
stringValues.add(value.outValue());
}
- InvokeNewArray invoke = new InvokeNewArray(
- dexItemFactory.stringArrayType, newArray.outValue(), stringValues);
- invoke.setPosition(newArray.getPosition());
- it.detach();
+ Value invokeValue = code.createValue(newArray.outType(), newArray.getLocalInfo());
+ InvokeNewArray invoke =
+ new InvokeNewArray(dexItemFactory.stringArrayType, invokeValue, stringValues);
for (Value value : newArray.inValues()) {
value.removeUser(newArray);
}
- instructionToInsertForArray.put(newArray.outValue(), invoke);
+ newArray.outValue().replaceUsers(invokeValue);
+ it.removeOrReplaceByDebugLocalRead();
+ instructionToInsertForArray.put(invokeValue, invoke);
+ storesToRemoveForArray.put(invokeValue, size);
} else {
// If there is only one element it is typically smaller to generate the array put
// instruction instead of fill array data.
@@ -2156,12 +2175,12 @@
continue;
}
int arraySize = newArray.size().getConstInstruction().asConstNumber().getIntValue();
- NewArrayFilledData fillArray = new NewArrayFilledData(
- newArray.outValue(), elementSize, arraySize, contents);
+ NewArrayFilledData fillArray =
+ new NewArrayFilledData(newArray.outValue(), elementSize, arraySize, contents);
fillArray.setPosition(newArray.getPosition());
it.add(fillArray);
+ storesToRemoveForArray.put(newArray.outValue(), size);
}
- storesToRemoveForArray.put(newArray.outValue(), size);
}
// Second pass: remove all the array put instructions for the array for which we have
// inserted a fill array data instruction instead.
@@ -2184,9 +2203,9 @@
storesToRemoveForArray.put(array, --toRemoveCount);
Instruction construction = instructionToInsertForArray.get(array);
if (construction != null) {
- // Update the position of the array construction to be the position of the
+ // Set the position of the new array construction to be the position of the
// last removed put at which point we are now adding the construction.
- construction.forceSetPosition(instruction.getPosition());
+ construction.setPosition(instruction.getPosition());
it.add(construction);
}
}
@@ -2653,8 +2672,6 @@
Instruction insnGoto = throwNullInsnIterator.next();
assert insnGoto.isGoto();
throwNullInsnIterator.replaceCurrentInstruction(notReachableThrow);
- // Use position from original invoke to guarantee it has a real position.
- notReachableThrow.forceSetPosition(insn.getPosition());
}
}
code.removeUnreachableBlocks();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index e655c0e..fc11b78 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -67,10 +67,11 @@
}
private DexEncodedMethod validateCandidate(InvokeMethod invoke, DexType invocationContext) {
- DexEncodedMethod candidate = invoke.lookupSingleTarget(inliner.appInfo, invocationContext);
+ DexEncodedMethod candidate =
+ invoke.lookupSingleTarget(inliner.appView.appInfo(), invocationContext);
if ((candidate == null)
|| (candidate.getCode() == null)
- || inliner.appInfo.definitionFor(candidate.method.getHolder()).isLibraryClass()) {
+ || inliner.appView.appInfo().definitionFor(candidate.method.getHolder()).isLibraryClass()) {
if (info != null) {
info.exclude(invoke, "No inlinee");
}
@@ -90,12 +91,12 @@
private Reason computeInliningReason(DexEncodedMethod target) {
if (target.getOptimizationInfo().forceInline()
- || (inliner.appInfo.hasLiveness()
- && inliner.appInfo.withLiveness().forceInline.contains(target.method))) {
+ || (inliner.appView.appInfo().hasLiveness()
+ && inliner.appView.withLiveness().appInfo().forceInline.contains(target.method))) {
return Reason.FORCE;
}
- if (inliner.appInfo.hasLiveness()
- && inliner.appInfo.withLiveness().alwaysInline.contains(target.method)) {
+ if (inliner.appView.appInfo().hasLiveness()
+ && inliner.appView.withLiveness().appInfo().alwaysInline.contains(target.method)) {
return Reason.ALWAYS;
}
if (callSiteInformation.hasSingleCallSite(target)) {
@@ -117,7 +118,7 @@
if (method.method.getHolder() == targetHolder) {
return true;
}
- DexClass clazz = inliner.appInfo.definitionFor(targetHolder);
+ DexClass clazz = inliner.appView.appInfo().definitionFor(targetHolder);
assert clazz != null;
if (target.getOptimizationInfo().triggersClassInitBeforeAnySideEffect()) {
return true;
@@ -135,7 +136,7 @@
* methods.
*/
private boolean classInitializationHasNoSideffects(DexType classToCheck) {
- DexClass clazz = inliner.appInfo.definitionFor(classToCheck);
+ DexClass clazz = inliner.appView.appInfo().definitionFor(classToCheck);
if ((clazz == null)
|| clazz.hasNonTrivialClassInitializer()
|| clazz.defaultValuesForStaticFieldsMayTriggerAllocation()) {
@@ -191,7 +192,7 @@
return false;
}
- DexClass holder = inliner.appInfo.definitionFor(candidate.method.getHolder());
+ DexClass holder = inliner.appView.appInfo().definitionFor(candidate.method.getHolder());
if (holder.isInterface()) {
// Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception at
// runtime.
@@ -271,12 +272,12 @@
if (info != null) {
info.exclude(invoke, "receiver for candidate can be null");
}
- assert !inliner.appInfo.forceInline.contains(candidate.method);
+ assert !inliner.appView.appInfo().forceInline.contains(candidate.method);
return null;
}
Reason reason = computeInliningReason(candidate);
- if (!candidate.isInliningCandidate(method, reason, inliner.appInfo)) {
+ if (!candidate.isInliningCandidate(method, reason, inliner.appView.appInfo())) {
// Abort inlining attempt if the single target is not an inlining candidate.
if (info != null) {
info.exclude(invoke, "target is not identified for inlining");
@@ -303,7 +304,7 @@
Reason reason = computeInliningReason(candidate);
// Determine if this should be inlined no matter how big it is.
- if (!candidate.isInliningCandidate(method, reason, inliner.appInfo)) {
+ if (!candidate.isInliningCandidate(method, reason, inliner.appView.appInfo())) {
// Abort inlining attempt if the single target is not an inlining candidate.
if (info != null) {
info.exclude(invoke, "target is not identified for inlining");
@@ -388,7 +389,7 @@
}
assert IteratorUtils.peekNext(blockIterator) == state;
// TODO(b/72693244): could be done when Value is created.
- new TypeAnalysis(inliner.appInfo, code.method).narrowing(nonNullValues);
+ new TypeAnalysis(inliner.appView.appInfo(), code.method).narrowing(nonNullValues);
}
// TODO(b/72693244): need a test where refined env in inlinee affects the caller.
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
index e23b534..8c8f428 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
@@ -38,8 +38,8 @@
private final Map<DexType, Reference2IntMap<DexField>> ordinalsMaps = new IdentityHashMap<>();
public EnumOrdinalMapCollector(AppView<AppInfoWithLiveness> appView, InternalOptions options) {
- this.appInfo = appView.getAppInfo();
- this.graphLense = appView.getGraphLense();
+ this.appInfo = appView.appInfo();
+ this.graphLense = appView.graphLense();
this.options = options;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index fcb7293..000eac2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -6,13 +6,13 @@
import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -47,8 +47,8 @@
// Threshold found empirically by testing on GMS Core.
private static final int CONTROL_FLOW_RESOLUTION_BLOCKS_THRESHOLD = 15;
+ protected final AppView<? extends AppInfoWithLiveness> appView;
private final IRConverter converter;
- protected final AppInfoWithLiveness appInfo;
final InternalOptions options;
// State for inlining methods which are known to be called twice.
@@ -59,11 +59,14 @@
private final Set<DexMethod> blackList = Sets.newIdentityHashSet();
- public Inliner(IRConverter converter, InternalOptions options) {
+ public Inliner(
+ AppView<? extends AppInfoWithLiveness> appView,
+ IRConverter converter,
+ InternalOptions options) {
+ this.appView = appView;
this.converter = converter;
- this.appInfo = converter.appInfo.withLiveness();
this.options = options;
- fillInBlackList(appInfo);
+ fillInBlackList(appView.appInfo());
}
private void fillInBlackList(AppInfoWithLiveness appInfo) {
@@ -73,7 +76,7 @@
public boolean isBlackListed(DexEncodedMethod method) {
return blackList.contains(method.method)
- || appInfo.neverInline.contains(method.method)
+ || appView.appInfo().neverInline.contains(method.method)
|| TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(method.method, converter);
}
@@ -89,7 +92,7 @@
public ConstraintWithTarget computeInliningConstraint(IRCode code, DexEncodedMethod method) {
ConstraintWithTarget result = ConstraintWithTarget.ALWAYS;
- InliningConstraints inliningConstraints = new InliningConstraints(appInfo);
+ InliningConstraints inliningConstraints = new InliningConstraints(appView.appInfo());
InstructionIterator it = code.instructionIterator();
while (it.hasNext()) {
Instruction instruction = it.next();
@@ -100,7 +103,7 @@
break;
}
// TODO(b/111080693): we may need to collect all meaningful constraints.
- result = ConstraintWithTarget.meet(result, state, appInfo);
+ result = ConstraintWithTarget.meet(result, state, appView.appInfo());
}
return result;
}
@@ -110,7 +113,7 @@
return false;
}
// The class needs also to be visible for us to have access.
- DexClass targetClass = appInfo.definitionFor(target.method.holder);
+ DexClass targetClass = appView.appInfo().definitionFor(target.method.holder);
return isVisibleWithFlags(target.method.holder, method.method.holder, targetClass.accessFlags);
}
@@ -122,7 +125,7 @@
return target == context;
}
if (flags.isProtected()) {
- return context.isSubtypeOf(target, appInfo) || target.isSamePackage(context);
+ return context.isSubtypeOf(target, appView.appInfo()) || target.isSamePackage(context);
}
// package-private
return target.isSamePackage(context);
@@ -167,7 +170,7 @@
.collect(Collectors.toList());
for (DexEncodedMethod method : methods) {
DexEncodedMethod mappedMethod =
- converter.getGraphLense().mapDexEncodedMethod(appInfo, method);
+ converter.graphLense().mapDexEncodedMethod(appView.appInfo(), method);
converter.processMethod(
mappedMethod,
feedback,
@@ -412,16 +415,16 @@
public IRCode buildInliningIR(
ValueNumberGenerator generator,
- AppInfoWithSubtyping appInfo,
- GraphLense graphLense,
+ AppView<? extends AppInfoWithSubtyping> appView,
InternalOptions options,
Position callerPosition) {
// Build the IR for a yet not processed method, and perform minimal IR processing.
- Origin origin = appInfo.originFor(target.method.holder);
+ Origin origin = appView.appInfo().originFor(target.method.holder);
IRCode code =
- target.buildInliningIR(appInfo, graphLense, options, generator, callerPosition, origin);
+ target.buildInliningIR(
+ appView.appInfo(), appView.graphLense(), options, generator, callerPosition, origin);
if (!target.isProcessed()) {
- new LensCodeRewriter(graphLense, appInfo).rewrite(code, target);
+ new LensCodeRewriter(appView, options).rewrite(code, target);
}
return code;
}
@@ -477,7 +480,7 @@
if (instruction.inValues().contains(unInitializedObject)) {
if (instruction.isInvokeDirect() && !seenSuperInvoke) {
DexMethod target = instruction.asInvokeDirect().getInvokedMethod();
- seenSuperInvoke = appInfo.dexItemFactory.isConstructor(target);
+ seenSuperInvoke = appView.dexItemFactory().isConstructor(target);
boolean callOnConstructorThatCallsConstructorSameClass =
calleeMethodHolder == target.holder;
boolean callOnSupertypeOfThisInConstructor =
@@ -504,7 +507,7 @@
return false;
}
DexField field = instruction.asInstancePut().getField();
- DexEncodedField target = appInfo.lookupInstanceTarget(field.getHolder(), field);
+ DexEncodedField target = appView.appInfo().lookupInstanceTarget(field.getHolder(), field);
if (target != null && target.accessFlags.isFinal()) {
return false;
}
@@ -594,11 +597,10 @@
}
assert invokePosition.callerPosition == null
|| invokePosition.getOutermostCaller().method
- == converter.getGraphLense().getOriginalMethodSignature(method.method);
+ == converter.graphLense().getOriginalMethodSignature(method.method);
IRCode inlinee =
- result.buildInliningIR(code.valueNumberGenerator,
- appInfo, converter.getGraphLense(), options, invokePosition);
+ result.buildInliningIR(code.valueNumberGenerator, appView, options, invokePosition);
if (inlinee != null) {
if (block.hasCatchHandlers() && !(oracle instanceof ForcedInliningOracle)) {
// Inlining could lead to an explosion of move-exception and resolution moves. As an
@@ -652,7 +654,7 @@
strategy.markInlined(inlinee);
if (!strategy.exceededAllowance() || result.ignoreInstructionBudget()) {
iterator.inlineInvoke(
- appInfo, code, inlinee, blockIterator, blocksToRemove, downcast);
+ appView.appInfo(), code, inlinee, blockIterator, blocksToRemove, downcast);
strategy.updateTypeInformationIfNeeded(inlinee, blockIterator, block);
// If we inlined the invoke from a bridge method, it is no longer a bridge method.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 052c589..e02222f 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
@@ -865,7 +865,7 @@
if (outlineMethods.size() >= options.outline.threshold) {
for (DexEncodedMethod outlineMethod : outlineMethods) {
methodsSelectedForOutlining.add(
- converter.getGraphLense().mapDexEncodedMethod(appInfo, outlineMethod));
+ converter.graphLense().mapDexEncodedMethod(appInfo, outlineMethod));
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
index c2fbc9e..fbe2e93 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
@@ -71,8 +71,8 @@
private final Map<DexField, Int2ReferenceMap<DexField>> switchMaps = new IdentityHashMap<>();
public SwitchMapCollector(AppView<AppInfoWithLiveness> appView, InternalOptions options) {
- this.appInfo = appView.getAppInfo();
- this.graphLense = appView.getGraphLense();
+ this.appInfo = appView.appInfo();
+ this.graphLense = appView.graphLense();
this.options = options;
switchMapPrefix = appInfo.dexItemFactory.createString("$SwitchMap$");
intArrayType = appInfo.dexItemFactory.createType("[I");
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 9baa647..832fc56 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -457,9 +457,11 @@
return null;
}
- assert init.holder == eligibleClass
- : "Inlined constructor? [invoke: " + initInvoke +
- ", expected class: " + eligibleClass + "]";
+ if (init.holder != eligibleClass) {
+ // Calling a constructor on a class that is different from the type of the instance.
+ // Gracefully abort class inlining (see the test B116282409).
+ return null;
+ }
DexEncodedMethod definition = findSingleTarget(init, true);
if (definition == null || isProcessedConcurrently.test(definition)) {
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 b7c830f..916679d 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
@@ -362,9 +362,9 @@
}
if (!methodMapping.isEmpty() || fieldMapping.isEmpty()) {
- classStaticizer.converter.setGraphLense(
+ classStaticizer.converter.appView.setGraphLense(
new ClassStaticizerGraphLense(
- classStaticizer.converter.getGraphLense(),
+ classStaticizer.converter.graphLense(),
classStaticizer.factory,
fieldMapping,
methodMapping,
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
index f114a7e..25df058 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
@@ -35,9 +35,9 @@
private final SeedMapper seedMapper;
public ProguardMapApplier(AppView<AppInfoWithLiveness> appView, SeedMapper seedMapper) {
- assert appView.getGraphLense().isContextFreeForMethods();
- this.appInfo = appView.getAppInfo();
- this.previousLense = appView.getGraphLense();
+ assert appView.graphLense().isContextFreeForMethods();
+ this.appInfo = appView.appInfo();
+ this.previousLense = appView.graphLense();
this.seedMapper = seedMapper;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
index 50571f3..480eee0 100644
--- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -62,8 +62,8 @@
// Phase 2: Visit classes and promote class/member to public if possible.
timing.begin("Phase 2: promoteToPublic");
- DexType.forAllInterfaces(appView.getDexItemFactory(), this::publicizeType);
- publicizeType(appView.getDexItemFactory().objectType);
+ DexType.forAllInterfaces(appView.dexItemFactory(), this::publicizeType);
+ publicizeType(appView.dexItemFactory().objectType);
timing.end();
return lenseBuilder.build(appView);
@@ -94,7 +94,7 @@
return false;
}
- if (appView.getDexItemFactory().isClassConstructor(encodedMethod.method)) {
+ if (appView.dexItemFactory().isClassConstructor(encodedMethod.method)) {
return false;
}
@@ -105,7 +105,7 @@
}
assert accessFlags.isPrivate();
- if (appView.getDexItemFactory().isConstructor(encodedMethod.method)) {
+ if (appView.dexItemFactory().isConstructor(encodedMethod.method)) {
accessFlags.unsetPrivate();
accessFlags.setPublic();
return false;
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index c1d7403..0b6a84d 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -30,9 +30,9 @@
private final MemberRebindingLense.Builder builder;
public MemberRebindingAnalysis(AppView<AppInfoWithLiveness> appView) {
- assert appView.getGraphLense().isContextFreeForMethods();
- this.appInfo = appView.getAppInfo();
- this.lense = appView.getGraphLense();
+ assert appView.graphLense().isContextFreeForMethods();
+ this.appInfo = appView.appInfo();
+ this.lense = appView.graphLense();
this.builder = MemberRebindingLense.builder(appInfo);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
index ad7effd..b11393a 100644
--- a/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
+++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
@@ -27,8 +27,8 @@
ImmutableMap.of(),
null,
null,
- appView.getGraphLense(),
- appView.getAppInfo().dexItemFactory);
+ appView.graphLense(),
+ appView.dexItemFactory());
this.appView = appView;
this.publicizedMethods = publicizedMethods;
}
@@ -48,9 +48,9 @@
private boolean publicizedMethodIsPresentOnHolder(DexMethod method, DexEncodedMethod context) {
GraphLenseLookupResult lookup =
- appView.getGraphLense().lookupMethod(method, context, Type.VIRTUAL);
+ appView.graphLense().lookupMethod(method, context, Type.VIRTUAL);
DexMethod signatureInCurrentWorld = lookup.getMethod();
- DexClass clazz = appView.getAppInfo().definitionFor(signatureInCurrentWorld.holder);
+ DexClass clazz = appView.appInfo().definitionFor(signatureInCurrentWorld.holder);
assert clazz != null;
DexEncodedMethod actualEncodedTarget = clazz.lookupVirtualMethod(signatureInCurrentWorld);
assert actualEncodedTarget != null;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 5e03071..03272a5 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -88,6 +88,24 @@
*/
public class VerticalClassMerger {
+ public static class VerticallyMergedClasses {
+
+ private final Map<DexType, DexType> mergedClasses;
+
+ private VerticallyMergedClasses(Map<DexType, DexType> mergedClasses) {
+ this.mergedClasses = mergedClasses;
+ }
+
+ public DexType getTargetFor(DexType type) {
+ assert mergedClasses.containsKey(type);
+ return mergedClasses.get(type);
+ }
+
+ public boolean hasBeenMergedIntoSubtype(DexType type) {
+ return mergedClasses.containsKey(type);
+ }
+ }
+
private enum AbortReason {
ALREADY_MERGED,
ALWAYS_INLINE,
@@ -200,9 +218,9 @@
InternalOptions options,
Timing timing) {
this.application = application;
- this.appInfo = appView.getAppInfo();
+ this.appInfo = appView.appInfo();
this.executorService = executorService;
- this.graphLense = appView.getGraphLense();
+ this.graphLense = appView.graphLense();
this.methodPoolCollection = new MethodPoolCollection(application);
this.options = options;
this.renamedMembersLense = new VerticalClassMergerGraphLense.Builder();
@@ -213,6 +231,10 @@
initializeMergeCandidates(classes);
}
+ public VerticallyMergedClasses getMergedClasses() {
+ return new VerticallyMergedClasses(mergedClasses);
+ }
+
private void initializeMergeCandidates(Iterable<DexProgramClass> classes) {
for (DexProgramClass clazz : classes) {
if (isMergeCandidate(clazz, pinnedTypes) && isStillMergeCandidate(clazz)) {
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 a64e25d..37f57da 100644
--- a/src/main/java/com/android/tools/r8/utils/Reporter.java
+++ b/src/main/java/com/android/tools/r8/utils/Reporter.java
@@ -55,6 +55,14 @@
/**
* @throws AbortException always.
*/
+ public RuntimeException fatalError(String message) {
+ fatalError(new StringDiagnostic(message));
+ throw new Unreachable();
+ }
+
+ /**
+ * @throws AbortException always.
+ */
public RuntimeException fatalError(Diagnostic error) {
error(error);
failIfPendingErrors();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/B116282409.java b/src/test/java/com/android/tools/r8/ir/optimize/B116282409.java
new file mode 100644
index 0000000..6fe1f16
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/B116282409.java
@@ -0,0 +1,178 @@
+// 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;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.CompilationFailedException;
+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.jasmin.JasminBuilder;
+import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
+import com.android.tools.r8.jasmin.JasminTestBase;
+import com.android.tools.r8.utils.AbortException;
+import com.android.tools.r8.utils.AndroidApp;
+import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class B116282409 extends JasminTestBase {
+
+ private final Backend backend;
+
+ private final boolean enableVerticalClassMerging;
+
+ @Rule public ExpectedException exception = ExpectedException.none();
+
+ @Parameters(name = "Backend: {0}, vertical class merging: {1}")
+ public static Collection<Object[]> data() {
+ return ImmutableList.of(
+ new Object[] {Backend.CF, false},
+ new Object[] {Backend.CF, true},
+ new Object[] {Backend.DEX, false},
+ new Object[] {Backend.DEX, true});
+ }
+
+ public B116282409(Backend backend, boolean enableVerticalClassMerging) {
+ this.backend = backend;
+ this.enableVerticalClassMerging = enableVerticalClassMerging;
+ }
+
+ @Test
+ public void test() throws Exception {
+ JasminBuilder jasminBuilder = new JasminBuilder();
+
+ // Create a class A with a default constructor that prints "In A.<init>()".
+ ClassBuilder classBuilder = jasminBuilder.addClass("A");
+ classBuilder.addMethod(
+ "public",
+ "<init>",
+ ImmutableList.of(),
+ "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ "aload_0",
+ "invokespecial java/lang/Object/<init>()V",
+ "getstatic java/lang/System/out Ljava/io/PrintStream;",
+ "ldc \"In A.<init>()\"",
+ "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+ "return");
+
+ // Create a class B that inherits from A.
+ classBuilder = jasminBuilder.addClass("B", "A");
+
+ // Also add a simple method that the class inliner would inline.
+ classBuilder.addVirtualMethod(
+ "m", "I", ".limit stack 5", ".limit locals 5", "bipush 42", "ireturn");
+
+ // Add a test class that initializes an instance of B using A.<init>.
+ classBuilder = jasminBuilder.addClass("TestClass");
+ classBuilder.addMainMethod(
+ ".limit stack 5",
+ ".limit locals 5",
+ "getstatic java/lang/System/out Ljava/io/PrintStream;",
+ "new B",
+ "dup",
+ "invokespecial A/<init>()V", // NOTE: usually B.<init>
+ "invokevirtual B/m()I",
+ "invokevirtual java/io/PrintStream/println(I)V",
+ "return");
+
+ // Build app.
+ if (enableVerticalClassMerging) {
+ exception.expect(CompilationFailedException.class);
+ exception.expectCause(
+ new CustomExceptionMatcher(
+ "Unable to rewrite `invoke-direct A.<init>(new B, ...)` in method "
+ + "`void TestClass.main(java.lang.String[])` after type `A` was merged into `B`.",
+ "Please add the following rule to your Proguard configuration file: "
+ + "`-keep,allowobfuscation class A`."));
+ }
+
+ AndroidApp output =
+ compileWithR8(
+ jasminBuilder.build(),
+ keepMainProguardConfiguration("TestClass"),
+ options -> options.enableVerticalClassMerging = enableVerticalClassMerging,
+ backend);
+ assertFalse(enableVerticalClassMerging);
+
+ // Run app.
+ ProcessResult vmResult = runOnVMRaw(output, "TestClass", backend);
+ if (backend == Backend.CF) {
+ // Verify that the input code does not run with java.
+ ProcessResult javaResult = runOnJavaRaw(jasminBuilder, "TestClass");
+ assertNotEquals(0, javaResult.exitCode);
+ assertThat(javaResult.stderr, containsString("VerifyError"));
+ assertThat(javaResult.stderr, containsString("Call to wrong initialization method"));
+
+ // The same should be true for the generated program.
+ assertNotEquals(0, vmResult.exitCode);
+ assertThat(vmResult.stderr, containsString("VerifyError"));
+ assertThat(vmResult.stderr, containsString("Call to wrong initialization method"));
+ } else {
+ assert backend == Backend.DEX;
+ if (ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+ assertNotEquals(0, vmResult.exitCode);
+ assertThat(
+ vmResult.stderr,
+ containsString("VFY: invoke-direct <init> on super only allowed for 'this' in <init>"));
+ } else {
+ assertEquals(0, vmResult.exitCode);
+ assertEquals(
+ String.join(System.lineSeparator(), "In A.<init>()", "42", ""), vmResult.stdout);
+ }
+ }
+ }
+
+ private static class CustomExceptionMatcher extends BaseMatcher<Throwable> {
+
+ private List<String> messages;
+
+ public CustomExceptionMatcher(String... messages) {
+ this.messages = Arrays.asList(messages);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description
+ .appendText("a string containing ")
+ .appendText(
+ String.join(
+ ", ", messages.stream().map(m -> "\"" + m + "\"").collect(Collectors.toList())));
+ }
+
+ @Override
+ public boolean matches(Object o) {
+ if (o instanceof AbortException) {
+ AbortException exception = (AbortException) o;
+ if (exception.getMessage() != null
+ && messages.stream().allMatch(message -> exception.getMessage().contains(message))) {
+ return true;
+ }
+ if (exception.getCause() != null) {
+ return matches(exception.getCause());
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index 3005c51..effd5a1 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -81,11 +81,6 @@
}
@Override
- public void detach() {
- remove();
- }
-
- @Override
public void set(Instruction instruction) {
it.set(instruction);
}
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 c1d9234..932c09b 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -75,7 +75,7 @@
ExecutorService executor = ThreadUtils.getExecutorService(1);
- AppInfoWithSubtyping appInfo = appView.getAppInfo();
+ AppInfoWithSubtyping appInfo = appView.appInfo();
RootSet rootSet = new RootSetBuilder(appInfo, program, configuration.getRules(), options)
.run(executor);
diff --git a/tools/gmscore_data.py b/tools/gmscore_data.py
index 8ff59df..e6d7677 100644
--- a/tools/gmscore_data.py
+++ b/tools/gmscore_data.py
@@ -72,10 +72,10 @@
},
'v9': {
'dex' : {
+ 'flags': '--no-desugaring',
'inputs': [os.path.join(V9_BASE, 'armv7_GmsCore_prod_alldpi_release.apk')],
+ 'main-dex-list': os.path.join(V9_BASE, 'main_dex_list.txt'),
'pgmap': '%s_proguard.map' % V9_PREFIX,
- 'libraries' : [ANDROID_JAR],
- 'min-api' : ANDROID_L_API,
},
'deploy' : {
'pgconf': ['%s_proguard.config' % V9_PREFIX],
@@ -83,18 +83,18 @@
'min-api' : ANDROID_L_API,
},
'proguarded' : {
+ 'flags': '--no-desugaring',
'inputs': ['%s_proguard.jar' % V9_PREFIX],
'main-dex-list': os.path.join(V9_BASE, 'main_dex_list.txt'),
'pgmap': '%s_proguard.map' % V9_PREFIX,
- 'min-api' : ANDROID_L_API,
}
},
'v10': {
'dex' : {
+ 'flags': '--no-desugaring',
'inputs': [os.path.join(V10_BASE, 'armv7_GmsCore_prod_alldpi_release.apk')],
+ 'main-dex-list': os.path.join(V10_BASE, 'main_dex_list.txt') ,
'pgmap': '%s_proguard.map' % V10_PREFIX,
- 'libraries' : [ANDROID_JAR],
- 'min-api' : ANDROID_L_API,
},
'deploy' : {
'inputs': ['%s_deploy.jar' % V10_PREFIX],
@@ -102,10 +102,10 @@
'min-api' : ANDROID_L_API,
},
'proguarded' : {
+ 'flags': '--no-desugaring',
'inputs': ['%s_proguard.jar' % V10_PREFIX],
'main-dex-list': os.path.join(V10_BASE, 'main_dex_list.txt') ,
'pgmap': '%s_proguard.map' % V10_PREFIX,
- 'min-api' : ANDROID_L_API,
}
},
'latest': {
@@ -117,10 +117,10 @@
'min-api' : ANDROID_L_API,
},
'proguarded' : {
+ 'flags': '--no-desugaring',
'inputs': ['%s_proguard.jar' % LATEST_PREFIX],
'main-dex-list': os.path.join(LATEST_BASE, 'main_dex_list.txt') ,
'pgmap': '%s_proguard.map' % LATEST_PREFIX,
- 'min-api' : ANDROID_L_API,
}
},
}
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 6493b2c..83163cb 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -215,6 +215,9 @@
if 'min-api' in values:
args.extend(['--min-api', values['min-api']])
+ if 'main-dex-list' in values:
+ args.extend(['--main-dex-list', values['main-dex-list']])
+
if options.compiler == 'r8':
if 'pgconf' in values and not options.k:
for pgconf in values['pgconf']:
@@ -234,10 +237,14 @@
and not os.path.exists(outdir):
os.makedirs(outdir)
+ # Additional flags for the compiler from the configuration file.
+ if 'flags' in values:
+ args.extend(values['flags'].split(' '))
if options.compiler == 'r8':
if 'r8-flags' in values:
args.extend(values['r8-flags'].split(' '))
+ # Additional flags for the compiler from the command line.
if options.compiler_flags:
args.extend(options.compiler_flags.split(' '))
if options.r8_flags: