Merge commit 'e6f2ba20fe5c7e7ef5d3b6ca6b4872b9e2f87cf1' into dev-release
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 0a7c0e5..fd550c1 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -551,12 +551,21 @@
@Override
public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ assert registry.getTraversalContinuation().shouldContinue();
ListIterator<CfInstruction> iterator = instructions.listIterator();
while (iterator.hasNext()) {
CfInstruction instruction = iterator.next();
instruction.registerUse(registry, method, iterator);
+ if (registry.getTraversalContinuation().shouldBreak()) {
+ return;
+ }
}
- tryCatchRanges.forEach(tryCatch -> tryCatch.internalRegisterUse(registry, method));
+ for (CfTryCatch tryCatch : tryCatchRanges) {
+ tryCatch.internalRegisterUse(registry, method);
+ if (registry.getTraversalContinuation().shouldBreak()) {
+ return;
+ }
+ }
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 589ae3a..2c36882 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -301,12 +301,19 @@
}
private void internalRegisterCodeReferences(DexClassAndMethod method, UseRegistry registry) {
+ assert registry.getTraversalContinuation().shouldContinue();
for (Instruction insn : instructions) {
insn.registerUse(registry);
+ if (registry.getTraversalContinuation().shouldBreak()) {
+ return;
+ }
}
for (TryHandler handler : handlers) {
for (TypeAddrPair pair : handler.pairs) {
registry.registerExceptionGuard(pair.type);
+ if (registry.getTraversalContinuation().shouldBreak()) {
+ return;
+ }
}
}
}
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 c68adac..b6c7d02 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -88,6 +88,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -1627,12 +1628,19 @@
public Builder adjustOptimizationInfoAfterRemovingThisParameter(
AppView<AppInfoWithLiveness> appView) {
- if (optimizationInfo.isMutableOptimizationInfo()) {
- optimizationInfo
- .asMutableMethodOptimizationInfo()
- .adjustOptimizationInfoAfterRemovingThisParameter(appView);
- }
- return this;
+ return modifyOptimizationInfo(
+ (newMethod, optimizationInfo) ->
+ optimizationInfo.adjustOptimizationInfoAfterRemovingThisParameter(appView));
+ }
+
+ public Builder modifyOptimizationInfo(
+ BiConsumer<DexEncodedMethod, MutableMethodOptimizationInfo> consumer) {
+ return addBuildConsumer(
+ newMethod -> {
+ if (optimizationInfo.isMutableOptimizationInfo()) {
+ consumer.accept(newMethod, optimizationInfo.asMutableMethodOptimizationInfo());
+ }
+ });
}
public Builder setCode(Code code) {
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 5d5a755..4d1790e 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -62,6 +62,11 @@
}
}
+ public <T> T registerCodeReferencesWithResult(UseRegistryWithResult<T> registry) {
+ registerCodeReferences(registry);
+ return registry.getResult();
+ }
+
@Override
public ProgramMethod getContext() {
return this;
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
index 4304fdd..98bf1c3 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -12,15 +12,16 @@
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
import it.unimi.dsi.fastutil.ints.Int2ReferenceRBTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
@@ -222,6 +223,10 @@
return this == EMPTY;
}
+ public Iterator<Entry<ArgumentInfo>> iterator() {
+ return argumentInfos.int2ReferenceEntrySet().iterator();
+ }
+
public boolean hasRemovedArguments() {
for (ArgumentInfo value : argumentInfos.values()) {
if (value.isRemovedArgumentInfo()) {
@@ -300,7 +305,7 @@
return params;
}
DexType[] newParams = new DexType[params.length - numberOfRemovedArguments()];
- int offset = encodedMethod.isStatic() ? 0 : 1;
+ int offset = encodedMethod.getFirstNonReceiverArgumentIndex();
int newParamIndex = 0;
for (int oldParamIndex = 0; oldParamIndex < params.length; oldParamIndex++) {
ArgumentInfo argInfo = argumentInfos.get(oldParamIndex + offset);
@@ -363,7 +368,7 @@
DexEncodedMethod method) {
if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
return builder -> {
- int firstArgumentIndex = BooleanUtils.intValue(!method.isStatic());
+ int firstArgumentIndex = method.getFirstNonReceiverArgumentIndex();
builder.removeParameterAnnotations(
oldIndex -> getArgumentInfo(oldIndex + firstArgumentIndex).isRemovedArgumentInfo());
};
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index c9c0bc9..3913383 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -4,11 +4,13 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.code.CfOrDexInstruction;
+import com.android.tools.r8.utils.TraversalContinuation;
import java.util.ListIterator;
public abstract class UseRegistry {
private DexItemFactory factory;
+ private TraversalContinuation continuation = TraversalContinuation.CONTINUE;
public enum MethodHandleUse {
ARGUMENT_TO_LAMBDA_METAFACTORY,
@@ -23,6 +25,15 @@
method.registerCodeReferences(this);
}
+ public void doBreak() {
+ assert continuation.shouldContinue();
+ continuation = TraversalContinuation.BREAK;
+ }
+
+ public TraversalContinuation getTraversalContinuation() {
+ return continuation;
+ }
+
public abstract void registerInitClass(DexType type);
public abstract void registerInvokeVirtual(DexMethod method);
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistryWithResult.java b/src/main/java/com/android/tools/r8/graph/UseRegistryWithResult.java
new file mode 100644
index 0000000..916a2f9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistryWithResult.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2021, 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.graph;
+
+public abstract class UseRegistryWithResult<T> extends UseRegistry {
+
+ private T result;
+
+ public UseRegistryWithResult(DexItemFactory factory) {
+ super(factory);
+ }
+
+ public UseRegistryWithResult(DexItemFactory factory, T defaultResult) {
+ super(factory);
+ this.result = defaultResult;
+ }
+
+ public T getResult() {
+ return result;
+ }
+
+ public void setResult(T result) {
+ this.result = result;
+ doBreak();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
index da12b74..036a381 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
@@ -42,8 +42,12 @@
}
private void registerReachableDefinitions(UseRegistry registry) {
+ assert registry.getTraversalContinuation().shouldContinue();
for (DexMethod typeConstructor : typeConstructors.values()) {
registry.registerInvokeDirect(typeConstructor);
+ if (registry.getTraversalContinuation().shouldBreak()) {
+ return;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
index 4402a83..c258558 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
@@ -17,8 +17,6 @@
public class VirtualMethodEntryPointSynthesizedCode extends SynthesizedCode {
private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
- private final DexItemFactory factory;
-
public VirtualMethodEntryPointSynthesizedCode(
Int2ReferenceSortedMap<DexMethod> mappedMethods,
DexField classIdField,
@@ -35,7 +33,6 @@
method,
position,
originalMethod));
- this.factory = factory;
this.mappedMethods = mappedMethods;
}
@@ -55,8 +52,12 @@
}
private void registerReachableDefinitions(UseRegistry registry) {
+ assert registry.getTraversalContinuation().shouldContinue();
for (DexMethod mappedMethod : mappedMethods.values()) {
registry.registerInvokeDirect(mappedMethod);
+ if (registry.getTraversalContinuation().shouldBreak()) {
+ return;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index 2be47ca..1e5a344 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -144,11 +144,10 @@
// We don't care about calls to native methods.
return;
}
- if (!appView.getKeepInfo(callee).isInliningAllowed(appView.options())) {
- // Since the callee is kept and optimizations are disallowed, we cannot inline it into the
- // caller, and we also cannot collect any optimization info for the method. Therefore, we
- // drop the call edge to reduce the total number of call graph edges, which should lead to
- // fewer call graph cycles.
+ if (appView.appInfo().isPinned(callee.getReference())) {
+ // Since the callee is kept, we cannot inline it into the caller, and we also cannot collect
+ // any optimization info for the method. Therefore, we drop the call edge to reduce the
+ // total number of call graph edges, which should lead to fewer call graph cycles.
return;
}
getOrCreateNode(callee).addCallerConcurrently(currentMethod, likelySpuriousCallEdge);
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 b35e2ca..b6ffb43 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
@@ -542,7 +542,7 @@
int originalNumberOfArguments =
method.getReference().proto.parameters.values.length
+ argumentsInfo.numberOfRemovedArguments()
- + (method.isStatic() ? 0 : 1)
+ + method.getFirstNonReceiverArgumentIndex()
- prototypeChanges.numberOfExtraParameters();
int usedArgumentIndex = 0;
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 e1c1ba6..60ecf33 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
@@ -1313,7 +1313,6 @@
.libraryMethodOptimizer()
.optimize(code, feedback, methodProcessor, methodProcessingContext);
timing.end();
- previous = printMethod(code, "IR after class library method optimizer (SSA)", previous);
assert code.isConsistentSSA();
}
@@ -1324,7 +1323,6 @@
timing.begin("Devirtualize invoke interface");
devirtualizer.devirtualizeInvokeInterface(code);
timing.end();
- previous = printMethod(code, "IR after devirtualizer (SSA)", previous);
}
assert code.verifyTypes(appView);
@@ -1401,14 +1399,12 @@
timing.begin("Rewrite throw NPE");
codeRewriter.rewriteThrowNullPointerException(code);
timing.end();
- previous = printMethod(code, "IR after rewrite throw null (SSA)", previous);
}
timing.begin("Optimize class initializers");
ClassInitializerDefaultsResult classInitializerDefaultsResult =
classInitializerDefaultsOptimization.optimize(code, feedback);
timing.end();
- previous = printMethod(code, "IR after class initializer optimisation (SSA)", previous);
if (Log.ENABLED) {
Log.debug(getClass(), "Intermediate (SSA) flow graph for %s:\n%s",
@@ -1420,7 +1416,7 @@
deadCodeRemover.run(code, timing);
assert code.isConsistentSSA();
- previous = printMethod(code, "IR after dead code removal (SSA)", previous);
+ previous = printMethod(code, "IR after lambda desugaring (SSA)", previous);
assert code.verifyTypes(appView);
@@ -1606,7 +1602,7 @@
timing.end();
}
- if (appView.getKeepInfo(code.context()).isPinned(options)) {
+ if (appView.getKeepInfo().getMethodInfo(code.context()).isPinned(options)) {
return;
}
@@ -1728,7 +1724,8 @@
|| definition.getOptimizationInfo().isReachabilitySensitive()) {
return false;
}
- if (!appView.getKeepInfo(method).isInliningAllowed(options)) {
+ if (appView.appInfo().hasLiveness()
+ && appView.appInfo().withLiveness().isPinned(method.getReference())) {
return false;
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index 13b7140..53bb277 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -66,6 +66,8 @@
void setEnumUnboxerMethodClassification(
ProgramMethod method, EnumUnboxerMethodClassification enumUnboxerMethodClassification);
+ void unsetEnumUnboxerMethodClassification(ProgramMethod method);
+
void setInstanceInitializerInfoCollection(
DexEncodedMethod method, InstanceInitializerInfoCollection instanceInitializerInfoCollection);
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 7bf0e38..0ddc915 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
@@ -118,7 +118,7 @@
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod singleTargetReference = singleTarget.getReference();
- if (!appView.getKeepInfo(singleTarget).isInliningAllowed(appView.options())) {
+ if (appInfo.isPinned(singleTargetReference)) {
whyAreYouNotInliningReporter.reportPinned();
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index b2e8366..df7eeb3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -305,7 +305,7 @@
ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder();
DexProto proto = encodedMethod.getReference().proto;
- int offset = encodedMethod.isStatic() ? 0 : 1;
+ int offset = encodedMethod.getFirstNonReceiverArgumentIndex();
for (int i = 0; i < proto.parameters.size(); ++i) {
DexType type = proto.parameters.values[i];
if (type.isAlwaysNull(appView)) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
index cc8f5b1..052e196 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -282,7 +282,7 @@
return null;
}
}
- int offset = method.accessFlags.isStatic() ? 0 : 1;
+ int offset = method.getFirstNonReceiverArgumentIndex();
int argumentCount = method.getReference().proto.parameters.size() + offset;
CollectUsedArguments collector = new CollectUsedArguments();
if (!method.accessFlags.isStatic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
index fd892c1..77d6178 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
@@ -4,8 +4,13 @@
package com.android.tools.r8.ir.optimize.enums.classification;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.utils.IteratorUtils;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
+import java.util.Iterator;
public final class CheckNotNullEnumUnboxerMethodClassification
extends EnumUnboxerMethodClassification {
@@ -31,6 +36,47 @@
}
@Override
+ public EnumUnboxerMethodClassification fixupAfterParameterRemoval(
+ ArgumentInfoCollection removedParameters) {
+ if (removedParameters.getArgumentInfo(argumentIndex).isRemovedArgumentInfo()) {
+ // If the null-checked argument is removed from the parameters of the method, then we can no
+ // longer classify this method as a check-not-null method. This is OK in terms of enum
+ // unboxing, since after the parameter removal enums at the call site will no longer have the
+ // check-not-null invoke instruction as a user.
+ //
+ // Note that when we materialize the enum instance in the check-not-null method, it is
+ // important that this method is reprocessed by enum unboxing (or that materialized instance
+ // would not be unboxed). This is guaranteed by argument removal: Since we have removed a
+ // parameter from the method, we will need to reprocess its code in the second optimization
+ // pass.
+ return unknown();
+ }
+
+ int numberOfArgumentsRemovedBeforeThis = 0;
+
+ Iterator<Entry<ArgumentInfo>> iterator = removedParameters.iterator();
+ while (iterator.hasNext()) {
+ Entry<ArgumentInfo> entry = iterator.next();
+ int argumentIndexForInfo = entry.getIntKey();
+ if (argumentIndexForInfo >= getArgumentIndex()) {
+ break;
+ }
+ ArgumentInfo argumentInfo = entry.getValue();
+ if (argumentInfo.isRemovedArgumentInfo()) {
+ numberOfArgumentsRemovedBeforeThis++;
+ }
+ }
+
+ assert IteratorUtils.allRemainingMatchDestructive(
+ iterator, entry -> entry.getIntKey() >= getArgumentIndex());
+
+ return numberOfArgumentsRemovedBeforeThis > 0
+ ? new CheckNotNullEnumUnboxerMethodClassification(
+ getArgumentIndex() - numberOfArgumentsRemovedBeforeThis)
+ : this;
+ }
+
+ @Override
public boolean isCheckNotNullClassification() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
index 2b34291..5c93c36 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
@@ -4,12 +4,17 @@
package com.android.tools.r8.ir.optimize.enums.classification;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+
public abstract class EnumUnboxerMethodClassification {
public static UnknownEnumUnboxerMethodClassification unknown() {
return UnknownEnumUnboxerMethodClassification.getInstance();
}
+ public abstract EnumUnboxerMethodClassification fixupAfterParameterRemoval(
+ ArgumentInfoCollection removedParameters);
+
public EnumUnboxerMethodClassification fixupAfterRemovingThisParameter() {
// Only static methods are currently classified by the enum unboxer.
assert isUnknownClassification();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
index 9f51d0a..e88239b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.optimize.enums.classification;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+
public final class UnknownEnumUnboxerMethodClassification extends EnumUnboxerMethodClassification {
private static final UnknownEnumUnboxerMethodClassification INSTANCE =
@@ -16,6 +18,12 @@
}
@Override
+ public EnumUnboxerMethodClassification fixupAfterParameterRemoval(
+ ArgumentInfoCollection removedParameters) {
+ return this;
+ }
+
+ @Override
public boolean isUnknownClassification() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
index d0c82cb..986ba65 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
@@ -85,7 +85,7 @@
}
private TypeElement[] getStaticTypes(AppView<?> appView, DexEncodedMethod method) {
- int argOffset = method.isStatic() ? 0 : 1;
+ int argOffset = method.getFirstNonReceiverArgumentIndex();
int size = method.getReference().getArity() + argOffset;
TypeElement[] staticTypes = new TypeElement[size];
if (!method.isStatic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 3efe7f6..4263b35 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -261,6 +261,10 @@
this.enumUnboxerMethodClassification = enumUnboxerMethodClassification;
}
+ void unsetEnumUnboxerMethodClassification() {
+ this.enumUnboxerMethodClassification = EnumUnboxerMethodClassification.unknown();
+ }
+
@Override
public TypeElement getDynamicUpperBoundType() {
return returnsObjectWithUpperBoundType;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index c9390d7..bd275db 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -272,6 +272,11 @@
}
@Override
+ public synchronized void unsetEnumUnboxerMethodClassification(ProgramMethod method) {
+ getMethodOptimizationInfoForUpdating(method).unsetEnumUnboxerMethodClassification();
+ }
+
+ @Override
public synchronized void setInstanceInitializerInfoCollection(
DexEncodedMethod method,
InstanceInitializerInfoCollection instanceInitializerInfoCollection) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index 623d8d2..1894532 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -122,6 +122,9 @@
ProgramMethod method, EnumUnboxerMethodClassification enumUnboxerMethodClassification) {}
@Override
+ public void unsetEnumUnboxerMethodClassification(ProgramMethod method) {}
+
+ @Override
public void setInstanceInitializerInfoCollection(
DexEncodedMethod method,
InstanceInitializerInfoCollection instanceInitializerInfoCollection) {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index fe00440..10649fb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -187,7 +187,15 @@
@Override
public void setEnumUnboxerMethodClassification(
ProgramMethod method, EnumUnboxerMethodClassification enumUnboxerMethodClassification) {
- // Ignored.
+ method
+ .getDefinition()
+ .getMutableOptimizationInfo()
+ .setEnumUnboxerMethodClassification(enumUnboxerMethodClassification);
+ }
+
+ @Override
+ public void unsetEnumUnboxerMethodClassification(ProgramMethod method) {
+ method.getDefinition().getMutableOptimizationInfo().unsetEnumUnboxerMethodClassification();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
index eb56742..6bd2080 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -4,22 +4,15 @@
package com.android.tools.r8.ir.synthetic;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.UseRegistry;
import java.util.function.Consumer;
-public class SynthesizedCode extends AbstractSynthesizedCode {
+public abstract class SynthesizedCode extends AbstractSynthesizedCode {
private final SourceCodeProvider sourceCodeProvider;
- private final Consumer<UseRegistry> registryCallback;
public SynthesizedCode(SourceCodeProvider sourceCodeProvider) {
- this(sourceCodeProvider, SynthesizedCode::registerReachableDefinitionsDefault);
- }
-
- private SynthesizedCode(SourceCodeProvider sourceCodeProvider, Consumer<UseRegistry> callback) {
this.sourceCodeProvider = sourceCodeProvider;
- this.registryCallback = callback;
}
@Override
@@ -28,11 +21,5 @@
}
@Override
- public Consumer<UseRegistry> getRegistryCallback() {
- return registryCallback;
- }
-
- private static void registerReachableDefinitionsDefault(UseRegistry registry) {
- throw new Unreachable();
- }
+ public abstract Consumer<UseRegistry> getRegistryCallback();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index f81b135..45420b6 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -21,11 +21,13 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
/** Optimization that propagates information about arguments from call sites to method entries. */
public class ArgumentPropagator {
@@ -139,8 +141,10 @@
// Using the computed optimization info, build a graph lens that describes the mapping from
// methods with constant parameters to methods with the constant parameters removed.
+ Set<DexProgramClass> affectedClasses = Sets.newConcurrentHashSet();
ArgumentPropagatorGraphLens graphLens =
- optimizeMethodParameters(stronglyConnectedProgramComponents, executorService);
+ optimizeMethodParameters(
+ stronglyConnectedProgramComponents, affectedClasses::add, executorService);
// Find all the code objects that need reprocessing.
new ArgumentPropagatorMethodReprocessingEnqueuer(appView)
@@ -148,7 +152,8 @@
// Finally, apply the graph lens to the program (i.e., remove constant parameters from method
// definitions).
- new ArgumentPropagatorApplicationFixer(appView, graphLens).fixupApplication(executorService);
+ new ArgumentPropagatorApplicationFixer(appView, graphLens)
+ .fixupApplication(affectedClasses, executorService);
timing.end();
}
@@ -184,12 +189,15 @@
/** Called by {@link IRConverter} to optimize method definitions. */
private ArgumentPropagatorGraphLens optimizeMethodParameters(
List<Set<DexProgramClass>> stronglyConnectedProgramComponents,
+ Consumer<DexProgramClass> affectedClassConsumer,
ExecutorService executorService)
throws ExecutionException {
Collection<ArgumentPropagatorGraphLens.Builder> partialGraphLensBuilders =
ThreadUtils.processItemsWithResults(
stronglyConnectedProgramComponents,
- classes -> new ArgumentPropagatorProgramOptimizer(appView).optimize(classes),
+ classes ->
+ new ArgumentPropagatorProgramOptimizer(appView)
+ .optimize(classes, affectedClassConsumer),
executorService);
// Merge all the partial, disjoint graph lens builders into a single graph lens.
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
index 346e3fc..71e4970 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -8,8 +8,14 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.MethodCollection;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -28,15 +34,19 @@
this.graphLens = graphLens;
}
- public void fixupApplication(ExecutorService executorService) throws ExecutionException {
+ public void fixupApplication(
+ Set<DexProgramClass> affectedClasses, ExecutorService executorService)
+ throws ExecutionException {
// If the graph lens is null, argument propagation did not lead to any parameter removals. In
// this case there is no needed to fixup the program.
if (graphLens == null) {
+ assert affectedClasses.isEmpty();
return;
}
- // TODO(b/190154391): Do not naively visit all classes, when only few require changes.
- ThreadUtils.processItems(appView.appInfo().classes(), this::fixupClass, executorService);
+ assert !affectedClasses.isEmpty();
+
+ ThreadUtils.processItems(affectedClasses, this::fixupClass, executorService);
appView.setGraphLens(graphLens);
}
@@ -55,6 +65,25 @@
methodReferenceAfterParameterRemoval,
builder -> {
// TODO(b/190154391): fixup parameter annotations, if any.
+ ArgumentInfoCollection removedParameters =
+ graphLens.getRemovedParameters(methodReferenceAfterParameterRemoval);
+ builder.modifyOptimizationInfo(
+ (newMethod, optimizationInfo) -> {
+ OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
+ ProgramMethod programMethod = new ProgramMethod(clazz, newMethod);
+ // TODO(b/190154391): test this.
+ EnumUnboxerMethodClassification rewrittenEnumUnboxerMethodClassification =
+ optimizationInfo
+ .getEnumUnboxerMethodClassification()
+ .fixupAfterParameterRemoval(removedParameters);
+ if (rewrittenEnumUnboxerMethodClassification.isCheckNotNullClassification()) {
+ feedback.setEnumUnboxerMethodClassification(
+ programMethod, rewrittenEnumUnboxerMethodClassification);
+ } else {
+ // Bypass monotonicity check.
+ feedback.unsetEnumUnboxerMethodClassification(programMethod);
+ }
+ });
});
});
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
index c60640c..a00c016 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
@@ -32,6 +32,11 @@
return new Builder(appView);
}
+ public ArgumentInfoCollection getRemovedParameters(DexMethod method) {
+ assert method != internalGetPreviousMethodSignature(method);
+ return removedParameters.getOrDefault(method, ArgumentInfoCollection.empty());
+ }
+
@Override
protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
@@ -40,8 +45,7 @@
assert !removedParameters.containsKey(method);
return prototypeChanges;
}
- return prototypeChanges.withRemovedArguments(
- removedParameters.getOrDefault(method, ArgumentInfoCollection.empty()));
+ return prototypeChanges.withRemovedArguments(getRemovedParameters(method));
}
@Override
@@ -79,13 +83,10 @@
public Builder recordMove(
DexMethod from, DexMethod to, ArgumentInfoCollection removedParametersForMethod) {
- if (from != to) {
- newMethodSignatures.put(from, to);
- if (!removedParametersForMethod.isEmpty()) {
- removedParameters.put(to, removedParametersForMethod);
- }
- } else {
- assert removedParametersForMethod.isEmpty();
+ assert from != to;
+ newMethodSignatures.put(from, to);
+ if (!removedParametersForMethod.isEmpty()) {
+ removedParameters.put(to, removedParametersForMethod);
}
return this;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index 3c732df..37adcfa 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.UseRegistryWithResult;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
@@ -93,8 +93,7 @@
method -> {
AffectedMethodUseRegistry registry =
new AffectedMethodUseRegistry(appView, graphLens);
- method.registerCodeReferences(registry);
- if (registry.isAffected()) {
+ if (method.registerCodeReferencesWithResult(registry)) {
methodsToReprocessInClass.add(method);
}
});
@@ -107,24 +106,20 @@
methodsToReprocessBuilder.addAll(methodsToReprocessForClass, currentGraphLens));
}
- static class AffectedMethodUseRegistry extends UseRegistry {
+ static class AffectedMethodUseRegistry extends UseRegistryWithResult<Boolean> {
private final AppView<AppInfoWithLiveness> appView;
private final ArgumentPropagatorGraphLens graphLens;
- // Set to true if the given piece of code resolves to a method that needs rewriting according to
- // the graph lens.
- private boolean affected;
-
AffectedMethodUseRegistry(
AppView<AppInfoWithLiveness> appView, ArgumentPropagatorGraphLens graphLens) {
- super(appView.dexItemFactory());
+ super(appView.dexItemFactory(), false);
this.appView = appView;
this.graphLens = graphLens;
}
- boolean isAffected() {
- return affected;
+ private void markAffected() {
+ setResult(Boolean.TRUE);
}
@Override
@@ -163,8 +158,7 @@
DexMethod rewrittenMethodReference =
graphLens.internalGetNextMethodSignature(resolvedMethod.getReference());
if (rewrittenMethodReference != resolvedMethod.getReference()) {
- affected = true;
- // TODO(b/150583533): break/abort!
+ markAffected();
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index b10ff8d..f469ddc 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
@@ -31,6 +32,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.function.IntPredicate;
public class ArgumentPropagatorProgramOptimizer {
@@ -68,7 +70,8 @@
// also enqueue the caller's callers for reprocessing. This would propagate the throwing
// information to all call sites.
public ArgumentPropagatorGraphLens.Builder optimize(
- Set<DexProgramClass> stronglyConnectedProgramClasses) {
+ Set<DexProgramClass> stronglyConnectedProgramClasses,
+ Consumer<DexProgramClass> affectedClassConsumer) {
// First reserve pinned method signatures.
reservePinnedMethodSignatures(stronglyConnectedProgramClasses);
@@ -83,7 +86,9 @@
ArgumentPropagatorGraphLens.Builder partialGraphLensBuilder =
ArgumentPropagatorGraphLens.builder(appView);
for (DexProgramClass clazz : stronglyConnectedProgramClasses) {
- visitClass(clazz, partialGraphLensBuilder);
+ if (visitClass(clazz, partialGraphLensBuilder)) {
+ affectedClassConsumer.accept(clazz);
+ }
}
return partialGraphLensBuilder;
}
@@ -200,8 +205,10 @@
return true;
}
- private void visitClass(
+ // Returns true if the class was changed as a result of argument propagation.
+ private boolean visitClass(
DexProgramClass clazz, ArgumentPropagatorGraphLens.Builder partialGraphLensBuilder) {
+ BooleanBox affected = new BooleanBox();
clazz.forEachProgramMethod(
method -> {
ArgumentInfoCollection removableParameters =
@@ -209,9 +216,13 @@
? computeRemovableParametersFromDirectMethod(method)
: computeRemovableParametersFromVirtualMethod(method);
DexMethod newMethodSignature = getNewMethodSignature(method, removableParameters);
- partialGraphLensBuilder.recordMove(
- method.getReference(), newMethodSignature, removableParameters);
+ if (newMethodSignature != method.getReference()) {
+ partialGraphLensBuilder.recordMove(
+ method.getReference(), newMethodSignature, removableParameters);
+ affected.set();
+ }
});
+ return affected.get();
}
private DexMethod getNewMethodSignature(
diff --git a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
index 4123c10..e0c7f83 100644
--- a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.ScopedDexMethodSet.AddMethodIfMoreVisibleResult;
import com.android.tools.r8.utils.IterableUtils;
-import java.util.ArrayList;
+import com.android.tools.r8.utils.ListUtils;
import java.util.List;
/**
@@ -58,32 +58,31 @@
if (virtualMethods == null) {
return null;
}
- // Removal of abstract methods is rare, so avoid copying the array until we find one.
- List<DexEncodedMethod> methods = null;
- for (int i = 0; i < virtualMethods.size(); i++) {
- DexEncodedMethod method = virtualMethods.get(i);
- if (scope.addMethodIfMoreVisible(method) != AddMethodIfMoreVisibleResult.NOT_ADDED
- || !method.accessFlags.isAbstract()
- || appView.appInfo().isPinned(method.getReference())) {
- if (methods != null) {
- methods.add(method);
- }
- } else {
- if (methods == null) {
- methods = new ArrayList<>(virtualMethods.size() - 1);
- for (int j = 0; j < i; j++) {
- methods.add(virtualMethods.get(j));
- }
- }
- if (Log.ENABLED) {
- Log.debug(getClass(), "Removing abstract method %s.", method.getReference());
- }
- }
+ // Removal of abstract methods is rare, ListUtils.filterOrElse does no copying if nothing is
+ // filtered out.
+ List<DexEncodedMethod> filteredMethods =
+ ListUtils.filterOrElse(virtualMethods, this::isNonAbstractPinnedOrWideningVisibility);
+ return filteredMethods == virtualMethods
+ ? null
+ : filteredMethods.toArray(DexEncodedMethod.EMPTY_ARRAY);
+ }
+
+ private boolean isNonAbstractPinnedOrWideningVisibility(DexEncodedMethod method) {
+ if (!method.accessFlags.isAbstract()) {
+ return true;
}
- if (methods != null) {
- return methods.toArray(DexEncodedMethod.EMPTY_ARRAY);
+ // Check if the method widens visibility. Adding to the scope mutates it.
+ if (scope.addMethodIfMoreVisible(method) != AddMethodIfMoreVisibleResult.NOT_ADDED) {
+ return true;
}
- return null;
+ if (appView.appInfo().isPinned(method.getReference())) {
+ return true;
+ }
+ // We will filter the method out since it is not pinned.
+ if (Log.ENABLED) {
+ Log.debug(getClass(), "Removing abstract method %s.", method.getReference());
+ }
+ return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 55278ec..acc8410 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -933,8 +933,7 @@
if (!options().enableValuePropagation || neverPropagateValue.contains(method)) {
return false;
}
- if (!method.getReturnType().isAlwaysNull(this)
- && !getKeepInfo().getMethodInfo(method, this).isInliningAllowed(options())) {
+ if (isPinned(method) && !method.getReturnType().isAlwaysNull(this)) {
return false;
}
return true;
@@ -1316,11 +1315,7 @@
if (refinedReceiverClass.isProgramClass()) {
DexClassAndMethod clazzAndMethod =
resolution.lookupVirtualDispatchTarget(refinedReceiverClass.asProgramClass(), this);
- if (clazzAndMethod == null
- || (clazzAndMethod.isProgramMethod()
- && !getKeepInfo()
- .getMethodInfo(clazzAndMethod.asProgramMethod())
- .isOptimizationAllowed(options()))) {
+ if (clazzAndMethod == null || isPinned(clazzAndMethod.getDefinition().getReference())) {
// TODO(b/150640456): We should maybe only consider program methods.
return DexEncodedMethod.SENTINEL;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
index 79fac0a..dd4226c 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -54,10 +54,6 @@
return this.equals(bottom());
}
- public boolean isInliningAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration);
- }
-
public static class Builder extends KeepInfo.Builder<Builder, KeepMethodInfo> {
private Builder() {
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 6a89e9b..6e06948 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -2186,6 +2186,7 @@
@Override
public Consumer<UseRegistry> getRegistryCallback() {
return registry -> {
+ assert registry.getTraversalContinuation().shouldContinue();
switch (type) {
case DIRECT:
registry.registerInvokeDirect(invocationTarget);
diff --git a/src/main/java/com/android/tools/r8/utils/IntObjToObjFunction.java b/src/main/java/com/android/tools/r8/utils/IntObjToObjFunction.java
index 9c07bed..b0ed4ee 100644
--- a/src/main/java/com/android/tools/r8/utils/IntObjToObjFunction.java
+++ b/src/main/java/com/android/tools/r8/utils/IntObjToObjFunction.java
@@ -6,5 +6,5 @@
public interface IntObjToObjFunction<S, T> {
- S apply(int i, T obj);
+ T apply(int i, S obj);
}
diff --git a/src/main/java/com/android/tools/r8/utils/IteratorUtils.java b/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
index 9420440..a34ec96 100644
--- a/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
@@ -165,6 +165,16 @@
return !anyRemainingMatch(iterator, remaining -> !predicate.test(remaining));
}
+ public static <T> boolean allRemainingMatchDestructive(
+ Iterator<T> iterator, Predicate<T> predicate) {
+ while (iterator.hasNext()) {
+ if (!predicate.test(iterator.next())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static <T> boolean anyRemainingMatch(ListIterator<T> iterator, Predicate<T> predicate) {
T state = peekNext(iterator);
boolean result = false;
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index 891f1c2..8fd84fc 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -159,6 +159,14 @@
return mapOrElse(list, fn, list);
}
+ /**
+ * Takes elements from the input list depending on the predicate being true. Returns the filtered
+ * list otherwise returns the original list of none were removed.
+ */
+ public static <T> List<T> filterOrElse(List<T> list, Predicate<T> predicate) {
+ return mapOrElse(list, element -> predicate.test(element) ? element : null, list);
+ }
+
public static <T> ArrayList<T> newArrayList(T element) {
ArrayList<T> list = new ArrayList<>(1);
list.add(element);
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/KeepAbstractMethodShadowingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/KeepAbstractMethodShadowingTest.java
new file mode 100644
index 0000000..04cacdf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/KeepAbstractMethodShadowingTest.java
@@ -0,0 +1,98 @@
+// Copyright (c) 2021, 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.bridgeremoval;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Assume;
+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 KeepAbstractMethodShadowingTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public KeepAbstractMethodShadowingTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ Assume.assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addProgramClasses(A.class, C.class, Main.class)
+ .addProgramClassFileData(getBWithAbstractFoo())
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(AbstractMethodError.class);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(A.class, C.class, Main.class)
+ .addProgramClassFileData(getBWithAbstractFoo())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .addKeepClassAndMembersRules(A.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(AbstractMethodError.class)
+ .inspectFailure(
+ inspector -> {
+ ClassSubject clazz = inspector.clazz(B.class);
+ assertThat(clazz, isPresent());
+ MethodSubject foo = clazz.uniqueMethodWithName("foo");
+ assertThat(foo, isPresent());
+ });
+ }
+
+ private byte[] getBWithAbstractFoo() throws Exception {
+ return transformer(B.class)
+ .renameMethod(MethodPredicate.onName("will_be_foo"), "foo")
+ .transform();
+ }
+
+ public static class A {
+ public void foo() {
+ System.out.println("Hello World");
+ }
+ }
+
+ public abstract static class B extends A {
+ public abstract void /* foo */ will_be_foo();
+ }
+
+ public static class C extends B {
+
+ @Override
+ public void foo() {
+ super.foo();
+ }
+
+ @Override
+ public void will_be_foo() {}
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ new C().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
index 31f87d9..640796d 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
@@ -102,7 +102,6 @@
.addKeepAttributeSourceFile()
.addKeepRules("-renamesourcefileattribute SourceFile")
.noTreeShaking()
- .addDontOptimize()
.run(parameters.getRuntime(), TestRunner.class, Boolean.toString(isDalvik))
.assertSuccess()
.getStdOut();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOptimize.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOptimize.java
deleted file mode 100644
index 0c0bac6..0000000
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOptimize.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2021, 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.inliner;
-
-import static org.junit.Assert.assertFalse;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import org.junit.Test;
-
-class Foobar {
- public static void main(String[] args) {
- System.out.println("Value: " + (new Bar()).returnPlusConstant(42));
- }
-}
-
-class Bar {
- public int returnPlusConstant(int value) {
- return value + 42;
- }
-}
-
-public class InliningOptimize extends TestBase {
-
- @Test
- public void test() throws Exception {
- testForR8(Backend.DEX)
- .addProgramClasses(Bar.class, Foobar.class)
- .addKeepRules("-keep,allowoptimization class ** {\n" + "*;\n" + "}")
- .compile()
- .inspect(
- inspector -> {
- inspector
- .clazz(Foobar.class)
- .mainMethod()
- .iterateInstructions(InstructionSubject::isInvoke)
- .forEachRemaining(
- invoke -> {
- assertFalse(
- invoke.getMethod().name.toString().contains("returnPlusConstant"));
- });
- })
- .run(Foobar.class)
- .assertSuccessWithOutputLines("Value: 84");
- }
-}
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 c6182b5..be4f6de 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -51,6 +51,7 @@
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi.RegisterReadType;
@@ -852,7 +853,12 @@
DexString.EMPTY_ARRAY);
Code code =
new SynthesizedCode(
- (ignored, callerPosition) -> new ReturnVoidCode(voidReturnMethod, callerPosition));
+ (ignored, callerPosition) -> new ReturnVoidCode(voidReturnMethod, callerPosition)) {
+ @Override
+ public Consumer<UseRegistry> getRegistryCallback() {
+ throw new Unreachable();
+ }
+ };
DexEncodedMethod method =
DexEncodedMethod.builder()
.setMethod(voidReturnMethod)
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index 42cd647..bcea2fe 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -391,7 +391,6 @@
.setMinApi(minSdk)
.noMinification()
.noTreeShaking()
- .addDontOptimize()
.setMainDexListConsumer(ToolHelper.consumeString(r8MainDexListOutput::set))
.allowDiagnosticMessages()
.compileWithExpectedDiagnostics(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java
new file mode 100644
index 0000000..ad4c08a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java
@@ -0,0 +1,99 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MixedArgumentRemovalAndEnumUnboxingTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(true))
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
+ .enableInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+
+ MethodSubject mainMethodSubject = mainClassSubject.mainMethod();
+ assertThat(mainMethodSubject, isPresent());
+ assertTrue(
+ mainMethodSubject
+ .streamInstructions()
+ .noneMatch(InstructionSubject::isConstNull));
+
+ MethodSubject testMethodSubject = mainClassSubject.uniqueMethodWithName("test");
+ assertThat(testMethodSubject, isPresent());
+ assertEquals(2, testMethodSubject.getProgramMethod().getReference().getArity());
+ assertEquals(
+ "int", testMethodSubject.getProgramMethod().getParameter(0).getTypeName());
+ assertEquals(
+ "int", testMethodSubject.getProgramMethod().getParameter(1).getTypeName());
+ assertTrue(
+ testMethodSubject.streamInstructions().noneMatch(InstructionSubject::isIf));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A", "B");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ MyEnum alwaysA = System.currentTimeMillis() >= 1 ? MyEnum.A : MyEnum.B;
+ MyEnum alwaysB = System.currentTimeMillis() >= 1 ? MyEnum.B : MyEnum.A;
+ test(null, alwaysA, null, alwaysB);
+ }
+
+ @NeverInline
+ static void test(Object alwaysNull, MyEnum alwaysA, Object alsoAlwaysNull, MyEnum alwaysB) {
+ if (alwaysNull == null && alsoAlwaysNull == null) {
+ System.out.println(alwaysA.name());
+ System.out.println(alwaysB.name());
+ }
+ }
+ }
+
+ enum MyEnum {
+ A,
+ B
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
index d68447d..252dcc5 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -105,7 +105,6 @@
.addKeepMainRule(Main.class)
.addKeepPackageNamesRule(getClass().getPackage())
.noTreeShaking()
- .addDontOptimize()
.addKeepAttributeSourceFile()
.addKeepAttributeLineNumberTable()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index c9d30fd..21501d0 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -85,8 +85,6 @@
return options -> {
// Disable inlining to make sure that code looks as expected.
options.enableInlining = false;
- // Disable the devirtulizer to not remove the super calls
- options.enableDevirtualization = false;
// Disable string concatenation optimization to not bother outlining of StringBuilder usage.
options.enableStringConcatenationOptimization = false;
// Also apply outline options.