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.