Require optimization info in DexEncodedMethod constructor
Previouosly toTypeSubstitutedMethod() would drop the call site optimization info. This changes the DexEncodedMethod constructor to explicitly take in CallSiteOptimizationInfo and MethodOptimization info, such that callers must provide appropriate values.
Since we no longer drop the call site optimziation info with this CL, this also adds appropriate rewriting of call site optimization info.
Change-Id: I64cd80f5bd062e59da2889174e36915368c41ed4
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 2e22011..49ad7d3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -13,6 +13,7 @@
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
import static com.android.tools.r8.utils.AndroidApiLevel.NOT_SET;
import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
+import static java.util.Objects.requireNonNull;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.cf.code.CfConstNull;
@@ -46,7 +47,6 @@
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
-import com.android.tools.r8.graph.DexEncodedMethod.CompilationState;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
import com.android.tools.r8.ir.code.IRCode;
@@ -57,6 +57,7 @@
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.ir.optimize.NestUtils;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
@@ -151,6 +152,8 @@
NOT_SET,
NOT_SET,
null,
+ CallSiteOptimizationInfo.top(),
+ DefaultMethodOptimizationInfo.getInstance(),
false);
public static final Int2ReferenceMap<DebugLocalInfo> NO_PARAMETER_INFO =
new Int2ReferenceArrayMap<>(0);
@@ -162,8 +165,8 @@
// TODO(b/128967328): towards finer-grained inlining constraints,
// we need to maintain a set of states with (potentially different) contexts.
private CompilationState compilationState = CompilationState.NOT_PROCESSED;
- private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
- private CallSiteOptimizationInfo callSiteOptimizationInfo = CallSiteOptimizationInfo.bottom();
+ private MethodOptimizationInfo optimizationInfo;
+ private CallSiteOptimizationInfo callSiteOptimizationInfo;
private CfVersion classFileVersion;
/** The apiLevelForCode describes the api level needed for knowing all references in the code */
private AndroidApiLevel apiLevelForCode;
@@ -243,6 +246,8 @@
AndroidApiLevel apiLevelForDefinition,
AndroidApiLevel apiLevelForCode,
CfVersion classFileVersion,
+ CallSiteOptimizationInfo callSiteOptimizationInfo,
+ MethodOptimizationInfo optimizationInfo,
boolean deprecated) {
super(method, annotations, d8R8Synthesized, apiLevelForDefinition);
this.accessFlags = accessFlags;
@@ -252,6 +257,8 @@
this.code = code;
this.classFileVersion = classFileVersion;
this.apiLevelForCode = apiLevelForCode;
+ this.callSiteOptimizationInfo = requireNonNull(callSiteOptimizationInfo);
+ this.optimizationInfo = requireNonNull(optimizationInfo);
assert accessFlags != null;
assert code == null || !shouldNotHaveCode();
assert parameterAnnotationsList != null;
@@ -1394,6 +1401,11 @@
callSiteOptimizationInfo = callSiteOptimizationInfo.join(other, appView, this);
}
+ public synchronized void setCallSiteOptimizationInfo(
+ CallSiteOptimizationInfo callSiteOptimizationInfo) {
+ this.callSiteOptimizationInfo = callSiteOptimizationInfo;
+ }
+
public void copyMetadata(DexEncodedMethod from) {
checkIfObsolete();
if (from.hasClassFileVersion()) {
@@ -1442,6 +1454,9 @@
private OptionalBool isLibraryMethodOverride = OptionalBool.UNKNOWN;
private ParameterAnnotationsList parameterAnnotations = ParameterAnnotationsList.empty();
private CompilationState compilationState = CompilationState.NOT_PROCESSED;
+ // TODO(b/190154391): We should set this to top, but the old call site optimization requires
+ // this to be bottom.
+ private CallSiteOptimizationInfo callSiteOptimizationInfo = CallSiteOptimizationInfo.bottom();
private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
private KotlinMethodLevelInfo kotlinInfo = getNoKotlinInfo();
private CfVersion classFileVersion = null;
@@ -1471,6 +1486,7 @@
code = from.getCode();
apiLevelForDefinition = from.getApiLevelForDefinition();
apiLevelForCode = from.getApiLevelForCode();
+ callSiteOptimizationInfo = from.getCallSiteOptimizationInfo();
optimizationInfo =
from.getOptimizationInfo().isMutableOptimizationInfo()
? from.getOptimizationInfo().asMutableMethodOptimizationInfo().mutableCopy()
@@ -1490,6 +1506,11 @@
}
}
+ public Builder apply(Consumer<Builder> consumer) {
+ consumer.accept(this);
+ return this;
+ }
+
public Builder applyIf(boolean condition, Consumer<Builder> thenConsumer) {
return applyIf(condition, thenConsumer, emptyConsumer());
}
@@ -1504,6 +1525,15 @@
return this;
}
+ public Builder fixupCallSiteOptimizationInfo(
+ Function<ConcreteCallSiteOptimizationInfo, ? extends CallSiteOptimizationInfo> fn) {
+ if (callSiteOptimizationInfo.isConcreteCallSiteOptimizationInfo()) {
+ callSiteOptimizationInfo =
+ fn.apply(callSiteOptimizationInfo.asConcreteCallSiteOptimizationInfo());
+ }
+ return this;
+ }
+
public Builder setSimpleInliningConstraint(
DexProgramClass holder, SimpleInliningConstraint simpleInliningConstraint) {
return addBuildConsumer(
@@ -1633,9 +1663,11 @@
public Builder adjustOptimizationInfoAfterRemovingThisParameter(
AppView<AppInfoWithLiveness> appView) {
- return modifyOptimizationInfo(
- (newMethod, optimizationInfo) ->
- optimizationInfo.adjustOptimizationInfoAfterRemovingThisParameter(appView));
+ return fixupCallSiteOptimizationInfo(
+ callSiteOptimizationInfo -> callSiteOptimizationInfo.fixupAfterParameterRemoval(0))
+ .modifyOptimizationInfo(
+ (newMethod, optimizationInfo) ->
+ optimizationInfo.adjustOptimizationInfoAfterRemovingThisParameter(appView));
}
public Builder modifyOptimizationInfo(
@@ -1719,10 +1751,11 @@
apiLevelForDefinition,
apiLevelForCode,
classFileVersion,
+ callSiteOptimizationInfo,
+ optimizationInfo,
deprecated);
result.setKotlinMemberInfo(kotlinInfo);
result.compilationState = compilationState;
- result.optimizationInfo = optimizationInfo;
if (!isLibraryMethodOverride.isUnknown()) {
result.setLibraryMethodOverride(isLibraryMethodOverride);
}
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 98bf1c3..7d65dc9 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -11,19 +11,26 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
+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.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.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
+import it.unimi.dsi.fastutil.ints.IntCollection;
+import it.unimi.dsi.fastutil.ints.IntList;
+import it.unimi.dsi.fastutil.ints.IntLists;
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;
+import java.util.function.Function;
public class RewrittenPrototypeDescription {
@@ -219,6 +226,25 @@
return argumentInfos.keySet();
}
+ public IntCollection getRemovedParameterIndices() {
+ int numberOfRemovedArguments = numberOfRemovedArguments();
+ if (numberOfRemovedArguments == 0) {
+ return IntLists.EMPTY_LIST;
+ }
+ if (numberOfRemovedArguments == argumentInfos.size()) {
+ return getKeys();
+ }
+ IntList removedParameterIndices = new IntArrayList(numberOfRemovedArguments);
+ Iterator<Entry<ArgumentInfo>> iterator = iterator();
+ while (iterator.hasNext()) {
+ Entry<ArgumentInfo> entry = iterator.next();
+ if (entry.getValue().isRemovedArgumentInfo()) {
+ removedParameterIndices.add(entry.getIntKey());
+ }
+ }
+ return removedParameterIndices;
+ }
+
public boolean isEmpty() {
return this == EMPTY;
}
@@ -364,6 +390,12 @@
return Integer.MAX_VALUE;
}
+ public Function<ConcreteCallSiteOptimizationInfo, ? extends CallSiteOptimizationInfo>
+ createCallSiteOptimizationInfoFixer() {
+ return callSiteOptimizationInfo ->
+ callSiteOptimizationInfo.fixupAfterParameterRemoval(getRemovedParameterIndices());
+ }
+
public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
DexEncodedMethod method) {
if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 9331f51..2c46605 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -519,6 +519,10 @@
newMethod,
builder ->
builder
+ .fixupCallSiteOptimizationInfo(
+ callSiteOptimizationInfo ->
+ callSiteOptimizationInfo.fixupAfterExtraNullParameters(
+ numberOfExtraNullParameters))
.setCompilationState(method.getCompilationState())
.setIsLibraryMethodOverrideIf(
method.isNonPrivateVirtualMethod(), OptionalBool.FALSE)
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 986ba65..a82770c 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
@@ -5,6 +5,8 @@
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
+import static com.android.tools.r8.utils.MapUtils.canonicalizeEmptyMap;
+import static java.util.Objects.requireNonNull;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -23,8 +25,11 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntCollection;
+import it.unimi.dsi.fastutil.ints.IntList;
import java.util.List;
-import java.util.Objects;
// Accumulated optimization info from call sites.
public class ConcreteCallSiteOptimizationInfo extends CallSiteOptimizationInfo {
@@ -36,10 +41,82 @@
private final Int2ReferenceMap<AbstractValue> constants;
private ConcreteCallSiteOptimizationInfo(int size, boolean allowConstantPropagation) {
+ this(
+ size,
+ new Int2ReferenceArrayMap<>(size),
+ allowConstantPropagation
+ ? new Int2ReferenceArrayMap<>(size)
+ : Int2ReferenceMaps.emptyMap());
+ }
+
+ private ConcreteCallSiteOptimizationInfo(
+ int size,
+ Int2ReferenceMap<TypeElement> dynamicUpperBoundTypes,
+ Int2ReferenceMap<AbstractValue> constants) {
assert size > 0;
this.size = size;
- this.dynamicUpperBoundTypes = new Int2ReferenceArrayMap<>(size);
- this.constants = allowConstantPropagation ? new Int2ReferenceArrayMap<>(size) : null;
+ this.dynamicUpperBoundTypes = requireNonNull(dynamicUpperBoundTypes);
+ this.constants = requireNonNull(constants);
+ }
+
+ private static CallSiteOptimizationInfo create(
+ int size,
+ Int2ReferenceMap<TypeElement> dynamicUpperBoundTypes,
+ Int2ReferenceMap<AbstractValue> constants) {
+ return constants.isEmpty() && dynamicUpperBoundTypes.isEmpty()
+ ? top()
+ : new ConcreteCallSiteOptimizationInfo(
+ size, canonicalizeEmptyMap(dynamicUpperBoundTypes), canonicalizeEmptyMap(constants));
+ }
+
+ public CallSiteOptimizationInfo fixupAfterExtraNullParameters(int extraNullParameters) {
+ return extraNullParameters > 0
+ ? new ConcreteCallSiteOptimizationInfo(
+ size + extraNullParameters, dynamicUpperBoundTypes, constants)
+ : this;
+ }
+
+ public CallSiteOptimizationInfo fixupAfterParameterRemoval(int removedParameterIndex) {
+ IntList removedParameterIndices = new IntArrayList(1);
+ removedParameterIndices.add(removedParameterIndex);
+ return fixupAfterParameterRemoval(removedParameterIndices);
+ }
+
+ public CallSiteOptimizationInfo fixupAfterParameterRemoval(
+ IntCollection removedParameterIndices) {
+ if (removedParameterIndices.isEmpty()) {
+ return this;
+ }
+
+ assert removedParameterIndices.stream()
+ .allMatch(removedParameterIndex -> removedParameterIndex < size);
+
+ int newSize = size - removedParameterIndices.size();
+ if (newSize == 0) {
+ return top();
+ }
+
+ Int2ReferenceMap<AbstractValue> rewrittenConstants = new Int2ReferenceArrayMap<>(newSize);
+ Int2ReferenceMap<TypeElement> rewrittenDynamicUpperBoundTypes =
+ new Int2ReferenceArrayMap<>(newSize);
+ for (int parameterIndex = 0, rewrittenParameterIndex = 0;
+ parameterIndex < size;
+ parameterIndex++) {
+ if (!removedParameterIndices.contains(parameterIndex)) {
+ AbstractValue abstractValue =
+ constants.getOrDefault(parameterIndex, AbstractValue.unknown());
+ if (!abstractValue.isUnknown()) {
+ rewrittenConstants.put(rewrittenParameterIndex, abstractValue);
+ }
+ TypeElement dynamicUpperBoundType = dynamicUpperBoundTypes.get(parameterIndex);
+ if (dynamicUpperBoundType != null) {
+ rewrittenDynamicUpperBoundTypes.put(rewrittenParameterIndex, dynamicUpperBoundType);
+ }
+ rewrittenParameterIndex++;
+ }
+ }
+ return ConcreteCallSiteOptimizationInfo.create(
+ newSize, rewrittenDynamicUpperBoundTypes, rewrittenConstants);
}
CallSiteOptimizationInfo join(
@@ -52,7 +129,6 @@
new ConcreteCallSiteOptimizationInfo(size, allowConstantPropagation);
for (int i = 0; i < result.size; i++) {
if (allowConstantPropagation) {
- assert result.constants != null;
AbstractValue abstractValue =
getAbstractArgumentValue(i)
.join(
@@ -137,17 +213,12 @@
@Override
public TypeElement getDynamicUpperBoundType(int argIndex) {
assert 0 <= argIndex && argIndex < size;
- assert dynamicUpperBoundTypes != null;
return dynamicUpperBoundTypes.getOrDefault(argIndex, null);
}
@Override
public AbstractValue getAbstractArgumentValue(int argIndex) {
assert 0 <= argIndex && argIndex < size;
- // TODO(b/69963623): Remove this once enabled.
- if (constants == null) {
- return UnknownValue.getInstance();
- }
return constants.getOrDefault(argIndex, UnknownValue.getInstance());
}
@@ -162,13 +233,11 @@
new ConcreteCallSiteOptimizationInfo(arguments.size(), allowConstantPropagation);
boolean hasReceiver = arguments.size() > invokedMethod.getArity();
boolean isTop = true;
- assert newCallSiteInfo.dynamicUpperBoundTypes != null;
for (int i = 0; i < newCallSiteInfo.size; i++) {
Value arg = arguments.get(i);
// Constant propagation.
if (allowConstantPropagation) {
- assert newCallSiteInfo.constants != null;
Value aliasedValue = arg.getAliasedValue();
if (!aliasedValue.isPhi()) {
AbstractValue abstractValue = aliasedValue.definition.getAbstractValue(appView, context);
@@ -278,13 +347,12 @@
return false;
}
ConcreteCallSiteOptimizationInfo otherInfo = (ConcreteCallSiteOptimizationInfo) other;
- return Objects.equals(this.dynamicUpperBoundTypes, otherInfo.dynamicUpperBoundTypes)
- && Objects.equals(this.constants, otherInfo.constants);
+ return dynamicUpperBoundTypes.equals(otherInfo.dynamicUpperBoundTypes)
+ && constants.equals(otherInfo.constants);
}
@Override
public int hashCode() {
- assert this.dynamicUpperBoundTypes != null;
return System.identityHashCode(dynamicUpperBoundTypes) * 7 + System.identityHashCode(constants);
}
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 71e4970..758ad2f 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
@@ -67,23 +67,27 @@
// 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);
- }
- });
+ builder
+ .fixupCallSiteOptimizationInfo(
+ removedParameters.createCallSiteOptimizationInfoFixer())
+ .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/utils/MapUtils.java b/src/main/java/com/android/tools/r8/utils/MapUtils.java
index 87c0856..a29af0b 100644
--- a/src/main/java/com/android/tools/r8/utils/MapUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MapUtils.java
@@ -5,6 +5,8 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.utils.StringUtils.BraceType;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.function.BiPredicate;
@@ -14,6 +16,10 @@
public class MapUtils {
+ public static <V> Int2ReferenceMap<V> canonicalizeEmptyMap(Int2ReferenceMap<V> map) {
+ return map.isEmpty() ? Int2ReferenceMaps.emptyMap() : map;
+ }
+
public static <K, V> Map<K, V> clone(
Map<K, V> mapToClone, Map<K, V> newMap, Function<V, V> valueCloner) {
mapToClone.forEach((key, value) -> newMap.put(key, valueCloner.apply(value)));