Remove uninstantiated type optimization pass
Change-Id: I4514f4d8342f4951683f5ee0db01b80d90903926
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 1f87898..0c8c20d 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -52,11 +52,8 @@
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.records.RecordRewriter;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
-import com.android.tools.r8.ir.optimize.MethodPoolCollection;
import com.android.tools.r8.ir.optimize.NestReducer;
import com.android.tools.r8.ir.optimize.SwitchMapCollector;
-import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization;
-import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.UninstantiatedTypeOptimizationGraphLens;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.ir.optimize.templates.CfUtilityMethodsForCodeOptimizations;
@@ -510,17 +507,6 @@
}
assert appView.verticallyMergedClasses() != null;
- if (options.enableUninstantiatedTypeOptimization) {
- timing.begin("UninstantiatedTypeOptimization");
- UninstantiatedTypeOptimizationGraphLens lens =
- new UninstantiatedTypeOptimization(appViewWithLiveness)
- .strenghtenOptimizationInfo()
- .run(new MethodPoolCollection(appViewWithLiveness), executorService, timing);
- assert lens == null || getDirectApp(appView).verifyNothingToRewrite(appView, lens);
- appView.rewriteWithLens(lens);
- timing.end();
- }
-
HorizontalClassMerger.createForInitialClassMerging(appViewWithLiveness)
.runIfNecessary(runtimeTypeCheckInfo, executorService, timing);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index c6bb8a7..04ba47d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -223,7 +223,7 @@
// We can exploit that a catch handler must be dead if its guard is never instantiated
// directly or indirectly.
- if (appInfoWithLiveness != null && appView.options().enableUninstantiatedTypeOptimization) {
+ if (appInfoWithLiveness != null) {
DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(guard));
if (clazz != null && !appInfoWithLiveness.isInstantiatedDirectlyOrIndirectly(clazz)) {
builder.add(new CatchHandler<>(guard, target));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
index 2b439a6..652c185 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
@@ -34,10 +34,6 @@
private final Predicate<DexEncodedMethod> methodTester;
- public MethodPoolCollection(AppView<AppInfoWithLiveness> appView) {
- this(appView, appView.appInfo().computeSubtypingInfo());
- }
-
public MethodPoolCollection(AppView<AppInfoWithLiveness> appView, SubtypingInfo subtypingInfo) {
this(appView, subtypingInfo, Predicates.alwaysTrue());
}
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
deleted file mode 100644
index df7eeb3..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.optimize;
-
-import static com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.Strategy.ALLOW_ARGUMENT_REMOVAL;
-import static com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.Strategy.DISALLOW_ARGUMENT_REMOVAL;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
-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.MethodSignatureEquivalence;
-import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
-import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
-import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-
-public class UninstantiatedTypeOptimization {
-
- enum Strategy {
- ALLOW_ARGUMENT_REMOVAL,
- DISALLOW_ARGUMENT_REMOVAL
- }
-
- public static class UninstantiatedTypeOptimizationGraphLens extends NestedGraphLens {
-
- private final Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod;
-
- UninstantiatedTypeOptimizationGraphLens(
- BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap,
- Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod,
- AppView<?> appView) {
- super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP);
- this.removedArgumentsInfoPerMethod = removedArgumentsInfoPerMethod;
- }
-
- @Override
- protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
- RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
- DexMethod previous = internalGetPreviousMethodSignature(method);
- if (previous == method) {
- assert !removedArgumentsInfoPerMethod.containsKey(method);
- return prototypeChanges;
- }
- if (method.getReturnType().isVoidType() && !previous.getReturnType().isVoidType()) {
- prototypeChanges =
- prototypeChanges.withConstantReturn(previous.getReturnType(), dexItemFactory());
- }
- return prototypeChanges.withRemovedArguments(
- removedArgumentsInfoPerMethod.getOrDefault(method, ArgumentInfoCollection.empty()));
- }
- }
-
- private static final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
-
- private final AppView<AppInfoWithLiveness> appView;
-
- public UninstantiatedTypeOptimization(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- }
-
- public UninstantiatedTypeOptimization strenghtenOptimizationInfo() {
- OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
- AbstractValue nullValue = appView.abstractValueFactory().createSingleNumberValue(0);
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- clazz.forEachField(
- field -> {
- if (field.type().isAlwaysNull(appView)) {
- feedback.recordFieldHasAbstractValue(field, appView, nullValue);
- }
- });
- clazz.forEachMethod(
- method -> {
- if (method.returnType().isAlwaysNull(appView)) {
- feedback.methodReturnsAbstractValue(method, appView, nullValue);
- }
- });
- }
- return this;
- }
-
- public UninstantiatedTypeOptimizationGraphLens run(
- MethodPoolCollection methodPoolCollection, ExecutorService executorService, Timing timing) {
- try {
- methodPoolCollection.buildAll(executorService, timing);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
- Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods = new HashMap<>();
- MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
- new BidirectionalOneToOneHashMap<>();
- Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod = new IdentityHashMap<>();
-
- TopDownClassHierarchyTraversal.forProgramClasses(appView)
- .visit(
- appView.appInfo().classes(),
- clazz ->
- processClass(
- clazz,
- changedVirtualMethods,
- methodMapping.getForwardMap(),
- methodPoolCollection,
- removedArgumentsInfoPerMethod));
-
- if (!methodMapping.isEmpty()) {
- return new UninstantiatedTypeOptimizationGraphLens(
- methodMapping, removedArgumentsInfoPerMethod, appView);
- }
- return null;
- }
-
- private void processClass(
- DexProgramClass clazz,
- Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods,
- BiMap<DexMethod, DexMethod> methodMapping,
- MethodPoolCollection methodPoolCollection,
- Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod) {
- MemberPool<DexMethod> methodPool = methodPoolCollection.get(clazz);
-
- if (clazz.isInterface()) {
- // Do not allow changing the prototype of methods that override an interface method.
- // This achieved by faking that there is already a method with the given signature.
- for (DexEncodedMethod virtualMethod : clazz.virtualMethods()) {
- RewrittenPrototypeDescription prototypeChanges =
- RewrittenPrototypeDescription.createForUninstantiatedTypes(
- virtualMethod.getReference(),
- appView,
- getRemovedArgumentsInfo(virtualMethod, ALLOW_ARGUMENT_REMOVAL));
- if (!prototypeChanges.isEmpty()) {
- DexMethod newMethod = getNewMethodSignature(virtualMethod, prototypeChanges);
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
- if (!methodPool.hasSeenDirectly(wrapper)) {
- methodPool.seen(wrapper);
- }
- }
- }
- return;
- }
-
- Map<DexEncodedMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
- new IdentityHashMap<>();
- for (DexEncodedMethod directMethod : clazz.directMethods()) {
- RewrittenPrototypeDescription prototypeChanges =
- getPrototypeChanges(directMethod, ALLOW_ARGUMENT_REMOVAL);
- if (!prototypeChanges.isEmpty()) {
- prototypeChangesPerMethod.put(directMethod, prototypeChanges);
- }
- }
-
- // Reserve all signatures which are known to not be touched below.
- Set<Wrapper<DexMethod>> usedSignatures = new HashSet<>();
- for (DexEncodedMethod method : clazz.methods()) {
- if (!prototypeChangesPerMethod.containsKey(method)) {
- usedSignatures.add(equivalence.wrap(method.getReference()));
- }
- }
-
- // Change the return type of direct methods that return an uninstantiated type to void.
- clazz
- .getMethodCollection()
- .replaceDirectMethods(
- encodedMethod -> {
- DexMethod method = encodedMethod.getReference();
- RewrittenPrototypeDescription prototypeChanges =
- prototypeChangesPerMethod.getOrDefault(
- encodedMethod, RewrittenPrototypeDescription.none());
- ArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getArgumentInfoCollection();
- DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
- if (newMethod != method) {
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
- // TODO(b/110806787): Can be extended to handle collisions by renaming the given
- // method.
- if (usedSignatures.add(wrapper)) {
- methodMapping.put(method, newMethod);
- if (removedArgumentsInfo.hasRemovedArguments()) {
- removedArgumentsInfoPerMethod.put(newMethod, removedArgumentsInfo);
- }
- return encodedMethod.toTypeSubstitutedMethod(
- newMethod,
- removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
- }
- }
- return encodedMethod;
- });
-
- // Change the return type of virtual methods that return an uninstantiated type to void.
- // This is done in two steps. First we change the return type of all methods that override
- // a method whose return type has already been changed to void previously. Note that
- // all supertypes of the current class are always visited prior to the current class.
- // This is important to ensure that a method that used to override a method in its super
- // class will continue to do so after this optimization.
- clazz
- .getMethodCollection()
- .replaceVirtualMethods(
- encodedMethod -> {
- DexMethod method = encodedMethod.getReference();
- RewrittenPrototypeDescription prototypeChanges =
- getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- ArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getArgumentInfoCollection();
- DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
- if (newMethod != method) {
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
- boolean isOverrideOfPreviouslyChangedMethodInSuperClass =
- changedVirtualMethods
- .getOrDefault(equivalence.wrap(method), ImmutableSet.of())
- .stream()
- .anyMatch(other -> appView.appInfo().isSubtype(clazz.type, other));
- if (isOverrideOfPreviouslyChangedMethodInSuperClass) {
- assert methodPool.hasSeen(wrapper);
-
- boolean signatureIsAvailable = usedSignatures.add(wrapper);
- assert signatureIsAvailable;
-
- methodMapping.put(method, newMethod);
- return encodedMethod.toTypeSubstitutedMethod(
- newMethod,
- removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
- }
- }
- return encodedMethod;
- });
- clazz
- .getMethodCollection()
- .replaceVirtualMethods(
- encodedMethod -> {
- DexMethod method = encodedMethod.getReference();
- RewrittenPrototypeDescription prototypeChanges =
- getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- ArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getArgumentInfoCollection();
- DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
- if (newMethod != method) {
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
- // TODO(b/110806787): Can be extended to handle collisions by renaming the given
- // method. Note that this also requires renaming all of the methods that override
- // this
- // method, though.
- if (!methodPool.hasSeen(wrapper) && usedSignatures.add(wrapper)) {
- methodPool.seen(wrapper);
-
- methodMapping.put(method, newMethod);
-
- boolean added =
- changedVirtualMethods
- .computeIfAbsent(
- equivalence.wrap(method), key -> Sets.newIdentityHashSet())
- .add(clazz.type);
- assert added;
-
- return encodedMethod.toTypeSubstitutedMethod(
- newMethod,
- removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
- }
- }
- return encodedMethod;
- });
- }
-
- private RewrittenPrototypeDescription getPrototypeChanges(
- DexEncodedMethod encodedMethod, Strategy strategy) {
- if (ArgumentRemovalUtils.isPinned(encodedMethod, appView)
- || appView.appInfo().isKeepConstantArgumentsMethod(encodedMethod.getReference())) {
- return RewrittenPrototypeDescription.none();
- }
- return RewrittenPrototypeDescription.createForUninstantiatedTypes(
- encodedMethod.getReference(), appView, getRemovedArgumentsInfo(encodedMethod, strategy));
- }
-
- private ArgumentInfoCollection getRemovedArgumentsInfo(
- DexEncodedMethod encodedMethod, Strategy strategy) {
- if (strategy == DISALLOW_ARGUMENT_REMOVAL) {
- return ArgumentInfoCollection.empty();
- }
-
- ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder();
- DexProto proto = encodedMethod.getReference().proto;
- int offset = encodedMethod.getFirstNonReceiverArgumentIndex();
- for (int i = 0; i < proto.parameters.size(); ++i) {
- DexType type = proto.parameters.values[i];
- if (type.isAlwaysNull(appView)) {
- RemovedArgumentInfo removedArg =
- RemovedArgumentInfo.builder()
- .setSingleValue(appView.abstractValueFactory().createNullValue())
- .setType(type)
- .build();
- argInfosBuilder.addArgumentInfo(i + offset, removedArg);
- }
- }
- return argInfosBuilder.build();
- }
-
- private DexMethod getNewMethodSignature(
- DexEncodedMethod encodedMethod, RewrittenPrototypeDescription prototypeChanges) {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- DexMethod method = encodedMethod.getReference();
- DexProto newProto = prototypeChanges.rewriteProto(encodedMethod, dexItemFactory);
-
- return dexItemFactory.createMethod(method.holder, newProto, method.name);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
index 2c93f77..b0b64ee 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
@@ -10,6 +10,8 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -37,10 +39,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == dexItemFactory.booleanMembers.booleanValue) {
optimizeBooleanValue(code, instructionIterator, invoke);
} else if (singleTarget.getReference() == dexItemFactory.booleanMembers.parseBoolean) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
index 5fb3d05..952d7cc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -33,10 +35,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == dexItemFactory.byteMembers.byteValue) {
optimizeByteValue(instructionIterator, invoke);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
index 5ee7017..167a528 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Assume;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -35,10 +37,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == appView.dexItemFactory().enumMembers.valueOf
&& invoke.inValues().get(0).isConstClass()) {
insertAssumeDynamicType(code, instructionIterator, invoke);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
index 1ce2493..935e869 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -115,48 +117,62 @@
MethodProcessor methodProcessor,
MethodProcessingContext methodProcessingContext) {
Set<Value> affectedValues = Sets.newIdentityHashSet();
- InstructionListIterator instructionIterator = code.instructionListIterator();
- Map<LibraryMethodModelCollection<?>, LibraryMethodModelCollection.State> optimizationStates =
- new IdentityHashMap<>();
- while (instructionIterator.hasNext()) {
- Instruction instruction = instructionIterator.next();
- if (!instruction.isInvokeMethod()) {
+ BasicBlockIterator blockIterator = code.listIterator();
+ Set<BasicBlock> blocksToRemove = Sets.newIdentityHashSet();
+ while (blockIterator.hasNext()) {
+ BasicBlock block = blockIterator.next();
+ if (blocksToRemove.contains(block)) {
continue;
}
- InvokeMethod invoke = instruction.asInvokeMethod();
- DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
- if (singleTarget == null) {
- continue;
- }
+ InstructionListIterator instructionIterator = block.listIterator(code);
+ Map<LibraryMethodModelCollection<?>, LibraryMethodModelCollection.State> optimizationStates =
+ new IdentityHashMap<>();
+ while (instructionIterator.hasNext()) {
+ Instruction instruction = instructionIterator.next();
+ if (!instruction.isInvokeMethod()) {
+ continue;
+ }
- LibraryMethodModelCollection<?> optimizer =
- libraryMethodModelCollections.get(singleTarget.getHolderType());
- if (optimizer == null) {
- continue;
- }
+ InvokeMethod invoke = instruction.asInvokeMethod();
+ DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
+ if (singleTarget == null) {
+ continue;
+ }
- if (invoke.hasUnusedOutValue()
- && !singleTarget.getDefinition().isInstanceInitializer()
- && !invoke.instructionMayHaveSideEffects(appView, code.context())) {
- instructionIterator.removeOrReplaceByDebugLocalRead();
- continue;
- }
+ LibraryMethodModelCollection<?> optimizer =
+ libraryMethodModelCollections.get(singleTarget.getHolderType());
+ if (optimizer == null) {
+ continue;
+ }
- LibraryMethodModelCollection.State optimizationState =
- optimizationStates.computeIfAbsent(
- optimizer,
- libraryMethodModelCollection ->
- libraryMethodModelCollection.createInitialState(methodProcessor));
- optimizer.optimize(
- code,
- instructionIterator,
- invoke,
- singleTarget,
- affectedValues,
- optimizationState,
- methodProcessingContext);
+ if (invoke.hasUnusedOutValue()
+ && !singleTarget.getDefinition().isInstanceInitializer()
+ && !invoke.instructionMayHaveSideEffects(appView, code.context())) {
+ instructionIterator.removeOrReplaceByDebugLocalRead();
+ continue;
+ }
+
+ LibraryMethodModelCollection.State optimizationState =
+ optimizationStates.computeIfAbsent(
+ optimizer,
+ libraryMethodModelCollection ->
+ libraryMethodModelCollection.createInitialState(methodProcessor));
+ optimizer.optimize(
+ code,
+ blockIterator,
+ instructionIterator,
+ invoke,
+ singleTarget,
+ affectedValues,
+ blocksToRemove,
+ optimizationState,
+ methodProcessingContext);
+ }
}
+
+ code.removeBlocks(blocksToRemove);
+
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
index da38111..dbc5b0b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -34,28 +36,34 @@
*/
void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
T state,
MethodProcessingContext methodProcessingContext);
@SuppressWarnings("unchecked")
default void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
Object state,
MethodProcessingContext methodProcessingContext) {
optimize(
code,
+ blockIterator,
instructionIterator,
invoke,
singleTarget,
affectedValues,
+ blocksToRemove,
(T) state,
methodProcessingContext);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
index aa93f3c..37ca53d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
@@ -9,6 +9,8 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -102,10 +104,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
int maxRemovedAndroidLogLevel =
appView.options().getProguardConfiguration().getMaxRemovedAndroidLogLevel();
if (singleTarget.getReference() == isLoggableMethod) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
index 2eeb165..e545164 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -32,8 +34,10 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {}
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
index c325500..98e0014 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -30,10 +32,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == dexItemFactory.objectMembers.getClass) {
optimizeGetClass(instructionIterator, invoke);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
index 1e518d6..7e55ce3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
@@ -11,6 +11,8 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -44,10 +46,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
DexMethod singleTargetReference = singleTarget.getReference();
switch (singleTargetReference.getName().byteAt(0)) {
case 'e':
@@ -72,7 +76,14 @@
break;
case 'r':
if (objectsMethods.isRequireNonNullMethod(singleTargetReference)) {
- optimizeRequireNonNull(instructionIterator, invoke, affectedValues, singleTarget);
+ optimizeRequireNonNull(
+ code,
+ blockIterator,
+ instructionIterator,
+ invoke,
+ affectedValues,
+ blocksToRemove,
+ singleTarget);
}
break;
case 't':
@@ -159,9 +170,12 @@
}
private void optimizeRequireNonNull(
+ IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
DexClassAndMethod singleTarget) {
if (invoke.hasOutValue() && invoke.outValue().hasLocalInfo()) {
// Replacing the out-value with an in-value would change debug info.
@@ -176,7 +190,13 @@
}
instructionIterator.removeOrReplaceByDebugLocalRead();
} else if (inValue.isAlwaysNull(appView)) {
- if (singleTarget.getReference() == objectsMethods.requireNonNullElse) {
+ if (singleTarget.getReference() == objectsMethods.requireNonNull) {
+ // Optimize Objects.requireNonNull(null) into throw null.
+ if (appView.hasClassHierarchy()) {
+ instructionIterator.replaceCurrentInstructionWithThrowNull(
+ appView.withClassHierarchy(), code, blockIterator, blocksToRemove, affectedValues);
+ }
+ } else if (singleTarget.getReference() == objectsMethods.requireNonNullElse) {
// Optimize Objects.requireNonNullElse(null, defaultObj) into defaultObj if defaultObj
// is never null.
if (invoke.getLastArgument().isNeverNull()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
index df15197..520c27a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
@@ -6,6 +6,8 @@
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -24,22 +26,33 @@
public abstract void optimize(
IRCode code,
- InstructionListIterator instructionIterator,
- InvokeMethod invoke,
- DexClassAndMethod singleTarget,
- Set<Value> affectedValues);
-
- @Override
- public final void optimize(
- IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove);
+
+ @Override
+ public final void optimize(
+ IRCode code,
+ BasicBlockIterator blockIterator,
+ InstructionListIterator instructionIterator,
+ InvokeMethod invoke,
+ DexClassAndMethod singleTarget,
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
State state,
MethodProcessingContext methodProcessingContext) {
assert state == null;
- optimize(code, instructionIterator, invoke, singleTarget, affectedValues);
+ optimize(
+ code,
+ blockIterator,
+ instructionIterator,
+ invoke,
+ singleTarget,
+ affectedValues,
+ blocksToRemove);
}
static class State implements LibraryMethodModelCollection.State {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
index 07ab344..8e03c61 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
@@ -18,6 +18,8 @@
import com.android.tools.r8.graph.DexItemFactory.StringBuildingMethods;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -67,10 +69,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
State state,
MethodProcessingContext methodProcessingContext) {
if (invoke.isInvokeMethodWithReceiver()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
index 8c62340..e5483db 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.DexItemBasedConstString;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -40,10 +42,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
DexMethod singleTargetReference = singleTarget.getReference();
if (singleTargetReference == dexItemFactory.stringMembers.equals) {
optimizeEquals(code, instructionIterator, invoke.asInvokeVirtual());
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 308862a..b5235d2 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -220,7 +220,6 @@
enableDevirtualization = false;
enableVerticalClassMerging = false;
enableEnumUnboxing = false;
- enableUninstantiatedTypeOptimization = false;
outline.enabled = false;
enableEnumValueOptimization = false;
enableValuePropagation = false;
@@ -329,7 +328,6 @@
public boolean enableInitializedClassesInInstanceMethodsAnalysis = true;
public boolean enableRedundantFieldLoadElimination = true;
public boolean enableValuePropagation = true;
- public boolean enableUninstantiatedTypeOptimization = true;
// Currently disabled, see b/146957343.
public boolean enableUninstantiatedTypeOptimizationForInterfaces = false;
// TODO(b/138917494): Disable until we have numbers on potential performance penalties.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
index ca64a9f..77da418 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
@@ -140,9 +140,7 @@
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- // TODO(b/157427150): would be able to remove the call to requireNonNull() if we knew that it
- // throws an NullPointerException that does not have a message.
- test(result, 0, 1);
+ test(result, 0, 0);
}
static class ObjectsRequireNonNullTestMain {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index f699bd7..615aa20 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -399,7 +399,6 @@
private void configure(InternalOptions options) {
options.enableClassInlining = false;
- options.enableUninstantiatedTypeOptimization = false;
}
@Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
index 06aae25..eca11f0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
@@ -64,10 +64,8 @@
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
.addOptionsModification(
- options -> {
- options.enableUninstantiatedTypeOptimization = enableArgumentPropagation;
- options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
- })
+ options ->
+ options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation))
// TODO(b/120764902): The calls to getOriginalName() below does not work in presence of
// argument removal.
.noMinification()