Merge commit '75d3c2a9584996d5ba82250273eb506cab57adf1' into dev-release
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 2906011..6c9025d 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -33,7 +33,6 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
@@ -153,18 +152,13 @@
code = buildEmptyThrowingCfCode(method.getReference());
}
DexEncodedMethod throwingMethod =
- new DexEncodedMethod(
- method.getReference(),
- method.accessFlags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- false,
- CfVersion.V1_6,
- AndroidApiLevel.UNKNOWN,
- AndroidApiLevel.UNKNOWN,
- false);
+ DexEncodedMethod.builder()
+ .setMethod(method.getReference())
+ .setAccessFlags(method.accessFlags)
+ .setGenericSignature(MethodTypeSignature.noSignature())
+ .setCode(code)
+ .setClassFileVersion(CfVersion.V1_6)
+ .build();
if (method.isStatic() || method.isDirectMethod()) {
directMethods.add(throwingMethod);
} else {
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index b279333..9336265 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -651,8 +651,13 @@
}
}
fields[i] =
- new DexEncodedField(
- field, accessFlags, fieldTypeSignature, fieldAnnotations, staticValue);
+ DexEncodedField.builder()
+ .setField(field)
+ .setAccessFlags(accessFlags)
+ .setGenericSignature(fieldTypeSignature)
+ .setAnnotations(fieldAnnotations)
+ .setStaticValue(staticValue)
+ .build();
}
return fields;
}
@@ -696,13 +701,14 @@
}
}
methods[i] =
- new DexEncodedMethod(
- method,
- accessFlags,
- methodTypeSignature,
- methodAnnotations,
- parameterAnnotationsIterator.getNextFor(method),
- code);
+ DexEncodedMethod.builder()
+ .setMethod(method)
+ .setAccessFlags(accessFlags)
+ .setGenericSignature(methodTypeSignature)
+ .setAnnotations(methodAnnotations)
+ .setParameterAnnotations(parameterAnnotationsIterator.getNextFor(method))
+ .setCode(code)
+ .build();
}
return methods;
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index ebbcd93..72cddc2 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -31,6 +31,7 @@
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
+import com.android.tools.r8.shaking.KeepMethodInfo;
import com.android.tools.r8.shaking.LibraryModeledPredicate;
import com.android.tools.r8.shaking.MainDexInfo;
import com.android.tools.r8.shaking.ProguardCompatibilityActions;
@@ -508,6 +509,10 @@
return keepInfo;
}
+ public KeepMethodInfo getKeepInfo(ProgramMethod method) {
+ return getKeepInfo().getMethodInfo(method);
+ }
+
public boolean hasProguardCompatibilityActions() {
return proguardCompatibilityActions != null;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 5efaba3..c89d8ed 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -32,9 +32,6 @@
public class DexEncodedField extends DexEncodedMember<DexEncodedField, DexField>
implements StructuralItem<DexEncodedField> {
- public static final boolean D8_R8_SYNTHESIZED = true;
- public static final boolean NOT_DEPRECATED = false;
- public static final DexValue NO_STATIC_VALUE = null;
public static final DexEncodedField[] EMPTY_ARRAY = {};
public final FieldAccessFlags accessFlags;
@@ -56,38 +53,7 @@
// TODO(b/171867022): Should the optimization info and member info be part of the definition?
}
- public DexEncodedField(DexField field, FieldAccessFlags accessFlags) {
- this(field, accessFlags, FieldTypeSignature.noSignature(), DexAnnotationSet.empty(), null);
- }
-
- public DexEncodedField(
- DexField field,
- FieldAccessFlags accessFlags,
- FieldTypeSignature genericSignature,
- DexAnnotationSet annotations,
- DexValue staticValue) {
- this(field, accessFlags, genericSignature, annotations, staticValue, false);
- }
-
- public DexEncodedField(
- DexField field,
- FieldAccessFlags accessFlags,
- FieldTypeSignature genericSignature,
- DexAnnotationSet annotations,
- DexValue staticValue,
- boolean deprecated) {
- this(
- field,
- accessFlags,
- genericSignature,
- annotations,
- staticValue,
- deprecated,
- false,
- AndroidApiLevel.UNKNOWN);
- }
-
- public DexEncodedField(
+ private DexEncodedField(
DexField field,
FieldAccessFlags accessFlags,
FieldTypeSignature genericSignature,
@@ -375,11 +341,15 @@
}
public static Builder builder() {
- return new Builder();
+ return new Builder(false);
}
private static Builder builder(DexEncodedField from) {
- return new Builder(from);
+ return new Builder(from.isD8R8Synthesized(), from);
+ }
+
+ public static Builder syntheticBuilder() {
+ return new Builder(true);
}
public static class Builder {
@@ -388,16 +358,18 @@
private DexAnnotationSet annotations = DexAnnotationSet.empty();
private FieldAccessFlags accessFlags;
private FieldTypeSignature genericSignature = FieldTypeSignature.noSignature();
- private DexValue staticValue;
- private AndroidApiLevel apiLevel;
+ private DexValue staticValue = null;
+ private AndroidApiLevel apiLevel = AndroidApiLevel.UNKNOWN;
private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
private boolean deprecated;
- private boolean d8R8Synthesized;
+ private final boolean d8R8Synthesized;
private Consumer<DexEncodedField> buildConsumer = ConsumerUtils.emptyConsumer();
- Builder() {}
+ private Builder(boolean d8R8Synthesized) {
+ this.d8R8Synthesized = d8R8Synthesized;
+ }
- Builder(DexEncodedField from) {
+ private Builder(boolean d8R8Synthesized, DexEncodedField from) {
// Copy all the mutable state of a DexEncodedField here.
field = from.getReference();
accessFlags = from.accessFlags.copy();
@@ -411,7 +383,7 @@
? from.optimizationInfo.asMutableFieldOptimizationInfo().mutableCopy()
: from.optimizationInfo;
deprecated = from.isDeprecated();
- d8R8Synthesized = from.isD8R8Synthesized();
+ this.d8R8Synthesized = d8R8Synthesized;
}
public Builder apply(Consumer<Builder> consumer) {
@@ -456,13 +428,23 @@
return this;
}
- public Builder setD8R8Synthesized() {
- this.d8R8Synthesized = true;
+ public Builder setApiLevel(AndroidApiLevel apiLevel) {
+ this.apiLevel = apiLevel;
return this;
}
- public Builder setApiLevel(AndroidApiLevel apiLevel) {
- this.apiLevel = apiLevel;
+ public Builder setGenericSignature(FieldTypeSignature genericSignature) {
+ this.genericSignature = genericSignature;
+ return this;
+ }
+
+ public Builder setStaticValue(DexValue staticValue) {
+ this.staticValue = staticValue;
+ return this;
+ }
+
+ public Builder setDeprecated(boolean deprecated) {
+ this.deprecated = deprecated;
return this;
}
@@ -471,7 +453,6 @@
assert accessFlags != null;
assert genericSignature != null;
assert annotations != null;
- assert apiLevel != null;
DexEncodedField dexEncodedField =
new DexEncodedField(
field,
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 6cbb223..c68adac 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -97,8 +97,6 @@
public class DexEncodedMethod extends DexEncodedMember<DexEncodedMethod, DexMethod>
implements StructuralItem<DexEncodedMethod> {
- public static final boolean D8_R8_SYNTHESIZED = true;
-
public static final String CONFIGURATION_DEBUGGING_PREFIX = "Shaking error: Missing method in ";
/**
@@ -145,7 +143,12 @@
MethodTypeSignature.noSignature(),
DexAnnotationSet.empty(),
ParameterAnnotationsList.empty(),
- null);
+ null,
+ false,
+ null,
+ AndroidApiLevel.UNKNOWN,
+ AndroidApiLevel.UNKNOWN,
+ false);
public static final Int2ReferenceMap<DebugLocalInfo> NO_PARAMETER_INFO =
new Int2ReferenceArrayMap<>(0);
@@ -201,6 +204,10 @@
return getReference().getArgumentType(argumentIndex, isStatic());
}
+ public int getFirstNonReceiverArgumentIndex() {
+ return isStatic() ? 0 : 1;
+ }
+
public int getNumberOfArguments() {
return getReference().getArity() + BooleanUtils.intValue(isInstance());
}
@@ -222,73 +229,7 @@
obsolete = false;
}
- public DexEncodedMethod(
- DexMethod method,
- MethodAccessFlags accessFlags,
- MethodTypeSignature genericSignature,
- DexAnnotationSet annotations,
- ParameterAnnotationsList parameterAnnotationsList,
- Code code) {
- this(
- method,
- accessFlags,
- genericSignature,
- annotations,
- parameterAnnotationsList,
- code,
- false,
- null,
- AndroidApiLevel.UNKNOWN,
- AndroidApiLevel.UNKNOWN);
- }
-
- public DexEncodedMethod(
- DexMethod method,
- MethodAccessFlags accessFlags,
- MethodTypeSignature genericSignature,
- DexAnnotationSet annotations,
- ParameterAnnotationsList parameterAnnotationsList,
- Code code,
- boolean d8R8Synthesized) {
- this(
- method,
- accessFlags,
- genericSignature,
- annotations,
- parameterAnnotationsList,
- code,
- d8R8Synthesized,
- null,
- AndroidApiLevel.UNKNOWN,
- AndroidApiLevel.UNKNOWN);
- }
-
- public DexEncodedMethod(
- DexMethod method,
- MethodAccessFlags accessFlags,
- MethodTypeSignature genericSignature,
- DexAnnotationSet annotations,
- ParameterAnnotationsList parameterAnnotationsList,
- Code code,
- boolean d8R8Synthesized,
- CfVersion classFileVersion,
- AndroidApiLevel apiLevelForDefinition,
- AndroidApiLevel apiLevelForCode) {
- this(
- method,
- accessFlags,
- genericSignature,
- annotations,
- parameterAnnotationsList,
- code,
- d8R8Synthesized,
- classFileVersion,
- apiLevelForDefinition,
- apiLevelForCode,
- false);
- }
-
- public DexEncodedMethod(
+ private DexEncodedMethod(
DexMethod method,
MethodAccessFlags accessFlags,
MethodTypeSignature genericSignature,
@@ -1316,18 +1257,19 @@
// Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
newFlags.setSynthetic();
newFlags.unsetAbstract();
- return new DexEncodedMethod(
- newMethod,
- newFlags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- ForwardMethodBuilder.builder(factory)
- .setNonStaticSource(newMethod)
- // Holder is companion class, or retarget method, not an interface.
- .setStaticTarget(forwardMethod, false)
- .build(),
- true);
+ // Holder is companion class, or retarget method, not an interface.
+ return syntheticBuilder()
+ .setMethod(newMethod)
+ .setAccessFlags(newFlags)
+ .setGenericSignature(MethodTypeSignature.noSignature())
+ .setAnnotations(DexAnnotationSet.empty())
+ .setCode(
+ ForwardMethodBuilder.builder(factory)
+ .setNonStaticSource(newMethod)
+ // Holder is companion class, or retarget method, not an interface.
+ .setStaticTarget(forwardMethod, false)
+ .build())
+ .build();
}
public DexEncodedMethod toStaticMethodWithoutThis(AppView<AppInfoWithLiveness> appView) {
@@ -1469,16 +1411,20 @@
this.genericSignature = MethodTypeSignature.noSignature();
}
+ public static Builder syntheticBuilder() {
+ return new Builder(true);
+ }
+
private static Builder syntheticBuilder(DexEncodedMethod from) {
- return new Builder(from, true);
+ return new Builder(true, from);
}
public static Builder builder() {
- return new Builder();
+ return new Builder(false);
}
private static Builder builder(DexEncodedMethod from) {
- return new Builder(from);
+ return new Builder(from.isD8R8Synthesized(), from);
}
public static class Builder {
@@ -1486,7 +1432,6 @@
private MethodAccessFlags accessFlags;
private Code code;
private DexMethod method;
-
private MethodTypeSignature genericSignature = MethodTypeSignature.noSignature();
private DexAnnotationSet annotations = DexAnnotationSet.empty();
private OptionalBool isLibraryMethodOverride = OptionalBool.UNKNOWN;
@@ -1495,19 +1440,23 @@
private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
private KotlinMethodLevelInfo kotlinInfo = getNoKotlinInfo();
private CfVersion classFileVersion = null;
- private AndroidApiLevel apiLevelForDefinition = null;
- private AndroidApiLevel apiLevelForCode = null;
- private boolean d8R8Synthesized = false;
+ private AndroidApiLevel apiLevelForDefinition = AndroidApiLevel.UNKNOWN;
+ private AndroidApiLevel apiLevelForCode = AndroidApiLevel.UNKNOWN;
+ private final boolean d8R8Synthesized;
+ private boolean deprecated = false;
+
+ // Checks to impose on the built method. They should always be active to start with and be
+ // lowered on the use site.
+ private boolean checkMethodNotNull = true;
+ private boolean checkParameterAnnotationList = true;
private Consumer<DexEncodedMethod> buildConsumer = ConsumerUtils.emptyConsumer();
- private Builder() {}
-
- private Builder(DexEncodedMethod from) {
- this(from, from.isD8R8Synthesized());
+ private Builder(boolean d8R8Synthesized) {
+ this.d8R8Synthesized = d8R8Synthesized;
}
- private Builder(DexEncodedMethod from, boolean d8R8Synthesized) {
+ private Builder(boolean d8R8Synthesized, DexEncodedMethod from) {
// Copy all the mutable state of a DexEncodedMethod here.
method = from.getReference();
accessFlags = from.getAccessFlags().copy();
@@ -1523,6 +1472,7 @@
kotlinInfo = from.getKotlinInfo();
classFileVersion = from.classFileVersion;
this.d8R8Synthesized = d8R8Synthesized;
+ deprecated = from.isDeprecated();
if (from.getParameterAnnotations().isEmpty()
|| from.getParameterAnnotations().size() == from.getParameters().size()) {
@@ -1574,11 +1524,6 @@
return this;
}
- public Builder setD8R8Synthesized() {
- this.d8R8Synthesized = true;
- return this;
- }
-
public Builder setMethod(DexMethod method) {
this.method = method;
return this;
@@ -1699,12 +1644,48 @@
return setCode(null);
}
+ public Builder setGenericSignature(MethodTypeSignature methodSignature) {
+ this.genericSignature = methodSignature;
+ return this;
+ }
+
+ public Builder setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) {
+ this.apiLevelForDefinition = apiLevelForDefinition;
+ return this;
+ }
+
+ public Builder setApiLevelForCode(AndroidApiLevel apiLevelForCode) {
+ this.apiLevelForCode = apiLevelForCode;
+ return this;
+ }
+
+ public Builder setDeprecated(boolean deprecated) {
+ this.deprecated = deprecated;
+ return this;
+ }
+
+ public Builder setClassFileVersion(CfVersion version) {
+ classFileVersion = version;
+ return this;
+ }
+
+ public Builder disableMethodNotNullCheck() {
+ checkMethodNotNull = false;
+ return this;
+ }
+
+ public Builder disableParameterAnnotationListCheck() {
+ checkParameterAnnotationList = false;
+ return this;
+ }
+
public DexEncodedMethod build() {
- assert method != null;
+ assert !checkMethodNotNull || method != null;
assert accessFlags != null;
assert annotations != null;
assert parameterAnnotations != null;
- assert parameterAnnotations.isEmpty()
+ assert !checkParameterAnnotationList
+ || parameterAnnotations.isEmpty()
|| parameterAnnotations.size() == method.proto.parameters.size();
assert apiLevelForDefinition != null;
assert apiLevelForCode != null;
@@ -1719,7 +1700,8 @@
d8R8Synthesized,
classFileVersion,
apiLevelForDefinition,
- apiLevelForCode);
+ apiLevelForCode,
+ deprecated);
result.setKotlinMemberInfo(kotlinInfo);
result.compilationState = compilationState;
result.optimizationInfo = optimizationInfo;
@@ -1729,20 +1711,5 @@
buildConsumer.accept(result);
return result;
}
-
- public Builder setGenericSignature(MethodTypeSignature methodSignature) {
- this.genericSignature = methodSignature;
- return this;
- }
-
- public Builder setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) {
- this.apiLevelForDefinition = apiLevelForDefinition;
- return this;
- }
-
- public Builder setApiLevelForCode(AndroidApiLevel apiLevelForCode) {
- this.apiLevelForCode = apiLevelForCode;
- return this;
- }
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 2f052aa..2164d54 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -668,13 +668,14 @@
createAnnotationSet(annotations, parent.application.options);
DexValue staticValue = flags.isStatic() ? getStaticValue(value, dexField.type) : null;
DexEncodedField field =
- new DexEncodedField(
- dexField,
- flags,
- fieldSignature,
- annotationSet,
- staticValue,
- AsmUtils.isDeprecated(access));
+ DexEncodedField.builder()
+ .setField(dexField)
+ .setAccessFlags(flags)
+ .setGenericSignature(fieldSignature)
+ .setAnnotations(annotationSet)
+ .setStaticValue(staticValue)
+ .setDeprecated(AsmUtils.isDeprecated(access))
+ .build();
if (flags.isStatic()) {
parent.staticFields.add(field);
} else {
@@ -902,18 +903,19 @@
parent.application.getFactory()));
}
DexEncodedMethod dexMethod =
- new DexEncodedMethod(
- method,
- flags,
- genericSignature,
- createAnnotationSet(annotations, options),
- parameterAnnotationsList,
- code,
- false,
- parent.version,
- AndroidApiLevel.UNKNOWN,
- AndroidApiLevel.UNKNOWN,
- deprecated);
+ DexEncodedMethod.builder()
+ .setMethod(method)
+ .setAccessFlags(flags)
+ .setGenericSignature(genericSignature)
+ .setAnnotations(createAnnotationSet(annotations, options))
+ .setParameterAnnotations(parameterAnnotationsList)
+ .setCode(code)
+ .setClassFileVersion(parent.version)
+ .setApiLevelForDefinition(AndroidApiLevel.UNKNOWN)
+ .setApiLevelForCode(AndroidApiLevel.UNKNOWN)
+ .setDeprecated(deprecated)
+ .disableParameterAnnotationListCheck()
+ .build();
Wrapper<DexMethod> signature = MethodSignatureEquivalence.get().wrap(method);
if (parent.methodSignatures.add(signature)) {
parent.hasReachabilitySensitiveMethod |= isReachabilitySensitive();
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 c016016..4304fdd 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.graph;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Position;
@@ -11,12 +13,13 @@
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.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.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@@ -68,11 +71,11 @@
public static class Builder {
- private boolean isAlwaysNull = false;
- private DexType type = null;
+ private SingleValue singleValue;
+ private DexType type;
- public Builder setIsAlwaysNull() {
- this.isAlwaysNull = true;
+ public Builder setSingleValue(SingleValue singleValue) {
+ this.singleValue = singleValue;
return this;
}
@@ -83,15 +86,15 @@
public RemovedArgumentInfo build() {
assert type != null;
- return new RemovedArgumentInfo(isAlwaysNull, type);
+ return new RemovedArgumentInfo(singleValue, type);
}
}
- private final boolean isAlwaysNull;
+ private final SingleValue singleValue;
private final DexType type;
- private RemovedArgumentInfo(boolean isAlwaysNull, DexType type) {
- this.isAlwaysNull = isAlwaysNull;
+ private RemovedArgumentInfo(SingleValue singleValue, DexType type) {
+ this.singleValue = singleValue;
this.type = type;
}
@@ -99,16 +102,20 @@
return new Builder();
}
+ public boolean hasSingleValue() {
+ return singleValue != null;
+ }
+
+ public SingleValue getSingleValue() {
+ return singleValue;
+ }
+
public DexType getType() {
return type;
}
- public boolean isAlwaysNull() {
- return isAlwaysNull;
- }
-
public boolean isNeverUsed() {
- return !isAlwaysNull;
+ return !hasSingleValue();
}
@Override
@@ -142,6 +149,16 @@
this.newType = newType;
}
+ public RewrittenTypeInfo combine(RewrittenPrototypeDescription other) {
+ return other.hasRewrittenReturnInfo() ? combine(other.getRewrittenReturnInfo()) : this;
+ }
+
+ public RewrittenTypeInfo combine(RewrittenTypeInfo other) {
+ assert !getNewType().isVoidType();
+ assert getNewType() == other.getOldType();
+ return new RewrittenTypeInfo(getOldType(), other.getNewType());
+ }
+
public DexType getNewType() {
return newType;
}
@@ -197,6 +214,10 @@
return EMPTY;
}
+ public IntSortedSet getKeys() {
+ return argumentInfos.keySet();
+ }
+
public boolean isEmpty() {
return this == EMPTY;
}
@@ -224,6 +245,10 @@
return argumentInfos.getOrDefault(argumentIndex, ArgumentInfo.NO_INFO);
}
+ public int size() {
+ return argumentInfos.size();
+ }
+
public static Builder builder() {
return new Builder();
}
@@ -248,6 +273,24 @@
}
}
+ public DexMethod rewriteMethod(ProgramMethod method, DexItemFactory dexItemFactory) {
+ if (isEmpty()) {
+ return method.getReference();
+ }
+ DexProto rewrittenProto = rewriteProto(method, dexItemFactory);
+ return method.getReference().withProto(rewrittenProto, dexItemFactory);
+ }
+
+ public DexProto rewriteProto(ProgramMethod method, DexItemFactory dexItemFactory) {
+ return isEmpty()
+ ? method.getProto()
+ : dexItemFactory.createProto(method.getReturnType(), rewriteParameters(method));
+ }
+
+ public DexType[] rewriteParameters(ProgramMethod method) {
+ return rewriteParameters(method.getDefinition());
+ }
+
public DexType[] rewriteParameters(DexEncodedMethod encodedMethod) {
// Currently not allowed to remove the receiver of an instance method. This would involve
// changing invoke-direct/invoke-virtual into invoke-static.
@@ -382,13 +425,38 @@
return NONE;
}
+ public RewrittenPrototypeDescription combine(RewrittenPrototypeDescription other) {
+ if (isEmpty()) {
+ return other;
+ }
+ if (other.isEmpty()) {
+ return this;
+ }
+ // We currently don't have any passes that remove extra parameters inserted by previous passes.
+ // If the input prototype changes have removed some of the extra parameters, we would need to
+ // adapt the merging of prototype changes below.
+ List<ExtraParameter> newExtraParameters =
+ ImmutableList.<ExtraParameter>builder()
+ .addAll(getExtraParameters())
+ .addAll(other.getExtraParameters())
+ .build();
+ RewrittenTypeInfo newRewrittenTypeInfo =
+ hasRewrittenReturnInfo()
+ ? getRewrittenReturnInfo().combine(other)
+ : other.getRewrittenReturnInfo();
+ ArgumentInfoCollection newArgumentInfoCollection =
+ getArgumentInfoCollection().combine(other.getArgumentInfoCollection());
+ return new RewrittenPrototypeDescription(
+ newExtraParameters, newRewrittenTypeInfo, newArgumentInfoCollection);
+ }
+
public boolean isEmpty() {
return extraParameters.isEmpty()
&& rewrittenReturnInfo == null
&& argumentInfoCollection.isEmpty();
}
- public Collection<ExtraParameter> getExtraParameters() {
+ public List<ExtraParameter> getExtraParameters() {
return extraParameters;
}
@@ -465,6 +533,18 @@
extraParameters, rewrittenReturnInfo, argumentInfoCollection.combine(other));
}
+ public RewrittenPrototypeDescription withRewrittenReturnInfo(
+ RewrittenTypeInfo rewrittenReturnInfo) {
+ if (rewrittenReturnInfo == null) {
+ return this;
+ }
+ if (!hasRewrittenReturnInfo()) {
+ return new RewrittenPrototypeDescription(
+ extraParameters, rewrittenReturnInfo, argumentInfoCollection);
+ }
+ throw new Unreachable();
+ }
+
public RewrittenPrototypeDescription withExtraUnusedNullParameter() {
return withExtraUnusedNullParameters(1);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 43a2c8a..b1055ef 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinition;
import com.android.tools.r8.graph.DexEncodedField;
@@ -21,10 +20,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMember;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
@@ -131,17 +127,14 @@
AndroidApiLevel apiReferenceLevel = classInitializerMerger.getApiReferenceLevel(appView);
DexEncodedMethod definition =
- new DexEncodedMethod(
- newMethodReference,
- MethodAccessFlags.createForClassInitializer(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- classInitializerMerger.getCode(syntheticMethodReference),
- DexEncodedMethod.D8_R8_SYNTHESIZED,
- classInitializerMerger.getCfVersion(),
- apiReferenceLevel,
- apiReferenceLevel);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(newMethodReference)
+ .setAccessFlags(MethodAccessFlags.createForClassInitializer())
+ .setCode(classInitializerMerger.getCode(syntheticMethodReference))
+ .setClassFileVersion(classInitializerMerger.getCfVersion())
+ .setApiLevelForDefinition(apiReferenceLevel)
+ .setApiLevelForCode(apiReferenceLevel)
+ .build();
classMethodsBuilder.addDirectMethod(definition);
// In case we didn't synthesize CF code, we register the class initializer for conversion to dex
@@ -218,18 +211,12 @@
assert appView.hasLiveness();
assert mode.isInitial();
- boolean deprecated = false;
- boolean d8R8Synthesized = true;
DexEncodedField classIdField =
- new DexEncodedField(
- group.getClassIdField(),
- FieldAccessFlags.createPublicFinalSynthetic(),
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- null,
- deprecated,
- d8R8Synthesized,
- minApiLevelIfEnabledOrUnknown(appView));
+ DexEncodedField.syntheticBuilder()
+ .setField(group.getClassIdField())
+ .setAccessFlags(FieldAccessFlags.createPublicFinalSynthetic())
+ .setApiLevel(minApiLevelIfEnabledOrUnknown(appView))
+ .build();
// For the $r8$classId synthesized fields, we try to over-approximate the set of values it may
// have. For example, for a merge group of size 4, we may compute the set {0, 2, 3}, if the
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index d6ae971..2ab6c46 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -11,15 +11,12 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexAnnotationSet;
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.DexType;
import com.android.tools.r8.graph.DexTypeUtils;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
import com.android.tools.r8.horizontalclassmerging.code.ConstructorEntryPointSynthesizedCode;
@@ -362,17 +359,15 @@
DexEncodedMethod representativeMethod = representative.getDefinition();
DexEncodedMethod newInstanceInitializer =
- new DexEncodedMethod(
- newMethodReference,
- getNewAccessFlags(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- getNewCode(newMethodReference, syntheticMethodReference, needsClassId, extraNulls),
- true,
- getNewClassFileVersion(),
- representativeMethod.getApiLevelForDefinition(),
- representativeMethod.getApiLevelForCode());
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(newMethodReference)
+ .setAccessFlags(getNewAccessFlags())
+ .setCode(
+ getNewCode(newMethodReference, syntheticMethodReference, needsClassId, extraNulls))
+ .setClassFileVersion(getNewClassFileVersion())
+ .setApiLevelForDefinition(representativeMethod.getApiLevelForDefinition())
+ .setApiLevelForCode(representativeMethod.getApiLevelForCode())
+ .build();
classMethodsBuilder.addDirectMethod(newInstanceInitializer);
if (mode.isFinal()) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index be6a5a2..62b09a6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -7,16 +7,13 @@
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotationSet;
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.DexType;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.code.VirtualMethodEntryPointSynthesizedCode;
import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
@@ -278,17 +275,14 @@
bridgeMethodReference,
appView.dexItemFactory());
DexEncodedMethod newMethod =
- new DexEncodedMethod(
- newMethodReference,
- getAccessFlags(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- synthesizedCode,
- true,
- classFileVersion,
- representativeMethod.getApiLevelForDefinition(),
- representativeMethod.getApiLevelForCode());
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(newMethodReference)
+ .setAccessFlags(getAccessFlags())
+ .setCode(synthesizedCode)
+ .setClassFileVersion(classFileVersion)
+ .setApiLevelForDefinition(representativeMethod.getApiLevelForDefinition())
+ .setApiLevelForCode(representativeMethod.getApiLevelForCode())
+ .build();
if (!representative.getDefinition().isLibraryMethodOverride().isUnknown()) {
newMethod.setLibraryMethodOverride(representative.getDefinition().isLibraryMethodOverride());
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index 8f4baa6..c42a3bb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -17,8 +17,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstClass;
-import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -64,7 +64,8 @@
@Override
public Instruction createMaterializingInstruction(
AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCode code,
+ ProgramMethod context,
+ NumberGenerator valueNumberGenerator,
TypeAndLocalInfoSupplier info) {
TypeElement typeLattice = info.getOutType();
DebugLocalInfo debugLocalInfo = info.getLocalInfo();
@@ -73,9 +74,12 @@
.isSubtype(appView.dexItemFactory().classType, typeLattice.asClassType().getClassType())
.isTrue();
Value returnedValue =
- code.createValue(classClassType(appView, definitelyNotNull()), debugLocalInfo);
+ new Value(
+ valueNumberGenerator.next(),
+ classClassType(appView, definitelyNotNull()),
+ debugLocalInfo);
ConstClass instruction = new ConstClass(returnedValue, type);
- assert !instruction.instructionMayHaveSideEffects(appView, code.context());
+ assert !instruction.instructionMayHaveSideEffects(appView, context);
return instruction;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
index 13df457..a537863 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
@@ -15,8 +15,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.DexItemBasedConstString;
-import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
@@ -74,7 +74,8 @@
@Override
public Instruction createMaterializingInstruction(
AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCode code,
+ ProgramMethod context,
+ NumberGenerator valueNumberGenerator,
TypeAndLocalInfoSupplier info) {
TypeElement typeLattice = info.getOutType();
DebugLocalInfo debugLocalInfo = info.getLocalInfo();
@@ -83,7 +84,10 @@
.isSubtype(appView.dexItemFactory().stringType, typeLattice.asClassType().getClassType())
.isTrue();
Value returnedValue =
- code.createValue(stringClassType(appView, definitelyNotNull()), debugLocalInfo);
+ new Value(
+ valueNumberGenerator.next(),
+ stringClassType(appView, definitelyNotNull()),
+ debugLocalInfo);
DexItemBasedConstString instruction =
new DexItemBasedConstString(returnedValue, item, nameComputationInfo);
assert !instruction.instructionInstanceCanThrow();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index 911174b..8769ab2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -17,8 +17,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
@@ -69,11 +69,12 @@
@Override
public Instruction createMaterializingInstruction(
AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCode code,
+ ProgramMethod context,
+ NumberGenerator valueNumberGenerator,
TypeAndLocalInfoSupplier info) {
TypeElement type = TypeElement.fromDexType(field.type, maybeNull(), appView);
assert type.lessThanOrEqual(info.getOutType(), appView);
- Value outValue = code.createValue(type, info.getLocalInfo());
+ Value outValue = new Value(valueNumberGenerator.next(), type, info.getLocalInfo());
return new StaticGet(outValue, field);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index d51b94a..c01133e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -11,8 +11,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -126,14 +126,17 @@
@Override
public Instruction createMaterializingInstruction(
AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCode code,
+ ProgramMethod context,
+ NumberGenerator valueNumberGenerator,
TypeAndLocalInfoSupplier info) {
TypeElement typeLattice = info.getOutType();
DebugLocalInfo debugLocalInfo = info.getLocalInfo();
assert !typeLattice.isReferenceType() || value == 0;
Value returnedValue =
- code.createValue(
- typeLattice.isReferenceType() ? TypeElement.getNull() : typeLattice, debugLocalInfo);
+ new Value(
+ valueNumberGenerator.next(),
+ typeLattice.isReferenceType() ? TypeElement.getNull() : typeLattice,
+ debugLocalInfo);
return new ConstNumber(returnedValue, value);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
index cd0c9e9..35acae4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -15,8 +15,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstString;
-import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -62,7 +62,8 @@
@Override
public Instruction createMaterializingInstruction(
AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCode code,
+ ProgramMethod context,
+ NumberGenerator valueNumberGenerator,
TypeAndLocalInfoSupplier info) {
TypeElement typeLattice = info.getOutType();
DebugLocalInfo debugLocalInfo = info.getLocalInfo();
@@ -71,7 +72,10 @@
.isSubtype(appView.dexItemFactory().stringType, typeLattice.asClassType().getClassType())
.isTrue();
Value returnedValue =
- code.createValue(stringClassType(appView, definitelyNotNull()), debugLocalInfo);
+ new Value(
+ valueNumberGenerator.next(),
+ stringClassType(appView, definitelyNotNull()),
+ debugLocalInfo);
ConstString instruction = new ConstString(returnedValue, string);
assert !instruction.instructionInstanceCanThrow();
return instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
index 4a3a11c..94cd837 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -35,9 +36,17 @@
* Note that calls to this method should generally be guarded by {@link
* #isMaterializableInContext}.
*/
- public abstract Instruction createMaterializingInstruction(
+ public final Instruction createMaterializingInstruction(
AppView<? extends AppInfoWithClassHierarchy> appView,
IRCode code,
+ TypeAndLocalInfoSupplier info) {
+ return createMaterializingInstruction(appView, code.context(), code.valueNumberGenerator, info);
+ }
+
+ public abstract Instruction createMaterializingInstruction(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProgramMethod context,
+ NumberGenerator valueNumberGenerator,
TypeAndLocalInfoSupplier info);
public abstract boolean isMaterializableInContext(
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index e06df9e..90ca265 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -123,6 +123,10 @@
public static ThrowingInfo defaultForConstString(InternalOptions options) {
return options.isGeneratingClassFiles() ? NO_THROW : CAN_THROW;
}
+
+ public static ThrowingInfo defaultForInstruction(Instruction instruction) {
+ return instruction.instructionTypeCanThrow() ? CAN_THROW : NO_THROW;
+ }
}
public enum EdgeType {
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 1e5a344..2be47ca 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,10 +144,11 @@
// We don't care about calls to native methods.
return;
}
- 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.
+ 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.
return;
}
getOrCreateNode(callee).addCallerConcurrently(currentMethod, likelySpuriousCallEdge);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 9f464b8..2b0cc34 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -848,6 +848,8 @@
@Override
public boolean verifyCurrentInstructionCanThrow() {
return isCurrentlyGeneratingMethodSynchronization()
+ // In the prelude we may be materializing arguments from call sites in R8.
+ || inPrelude
|| code.getInstructions().get(currentInstructionIndex).canThrow();
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 6c0279a..211f77b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -66,6 +66,7 @@
private Try currentTryRange = null;
private CatchHandlers<Integer> currentCatchHandlers = null;
private Instruction currentDexInstruction = null;
+ private boolean isBuildingPrelude;
private Position currentPosition = null;
private final CanonicalPositions canonicalPositions;
@@ -134,14 +135,16 @@
@Override
public void buildPrelude(IRBuilder builder) {
+ assert !isBuildingPrelude;
+ isBuildingPrelude = true;
currentPosition = canonicalPositions.getPreamblePosition();
- if (code.incomingRegisterSize == 0) {
- return;
+ if (code.incomingRegisterSize > 0) {
+ builder.buildArgumentsWithRewrittenPrototypeChanges(
+ code.registerSize - code.incomingRegisterSize,
+ method.getDefinition(),
+ DexSourceCode::doNothingWriteConsumer);
}
- builder.buildArgumentsWithRewrittenPrototypeChanges(
- code.registerSize - code.incomingRegisterSize,
- method.getDefinition(),
- DexSourceCode::doNothingWriteConsumer);
+ isBuildingPrelude = false;
}
public static void doNothingWriteConsumer(Integer register, DexType type) {
@@ -198,7 +201,8 @@
@Override
public boolean verifyCurrentInstructionCanThrow() {
- return currentDexInstruction.canThrow();
+ // In the prelude we may be materializing arguments from call sites in R8.
+ return isBuildingPrelude || currentDexInstruction.canThrow();
}
@Override
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 3911614..b35e2ca 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
@@ -43,6 +43,7 @@
import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.code.Add;
import com.android.tools.r8.ir.code.And;
import com.android.tools.r8.ir.code.Argument;
@@ -110,6 +111,7 @@
import com.android.tools.r8.ir.code.StaticPut;
import com.android.tools.r8.ir.code.Sub;
import com.android.tools.r8.ir.code.Throw;
+import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Ushr;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
@@ -1037,13 +1039,27 @@
private void handleConstantOrUnusedArgument(
int register, RemovedArgumentInfo removedArgumentInfo) {
assert removedArgumentInfo != null;
- if (removedArgumentInfo.isAlwaysNull()) {
+ if (removedArgumentInfo.hasSingleValue()) {
if (pendingArgumentInstructions == null) {
pendingArgumentInstructions = new ArrayList<>();
}
DebugLocalInfo local = getOutgoingLocal(register);
- Value value = writeRegister(register, getNull(), ThrowingInfo.NO_THROW, local);
- pendingArgumentInstructions.add(new ConstNumber(value, 0));
+ SingleValue singleValue = removedArgumentInfo.getSingleValue();
+ TypeElement type =
+ removedArgumentInfo.getType().isReferenceType() && singleValue.isNull()
+ ? getNull()
+ : removedArgumentInfo.getType().toTypeElement(appView);
+ Instruction materializingInstruction =
+ singleValue.createMaterializingInstruction(
+ appView.withClassHierarchy(),
+ method,
+ valueNumberGenerator,
+ TypeAndLocalInfoSupplier.create(type, local));
+ writeRegister(
+ register,
+ materializingInstruction.outValue(),
+ ThrowingInfo.defaultForInstruction(materializingInstruction));
+ pendingArgumentInstructions.add(materializingInstruction);
} else {
assert removedArgumentInfo.isNeverUsed();
}
@@ -2339,8 +2355,12 @@
// See addDebugLocalStart and addDebugLocalEnd.
private Value writeRegister(
int register, TypeElement typeLattice, ThrowingInfo throwing, DebugLocalInfo local) {
+ return writeRegister(
+ register, new Value(valueNumberGenerator.next(), typeLattice, local), throwing);
+ }
+
+ private Value writeRegister(int register, Value value, ThrowingInfo throwing) {
checkRegister(register);
- Value value = new Value(valueNumberGenerator.next(), typeLattice, local);
currentBlock.writeCurrentDefinition(register, value, throwing);
return value;
}
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 8f6f293..e1c1ba6 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
@@ -56,7 +56,6 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceApplicationRewriter;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
-import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover;
import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
@@ -100,6 +99,7 @@
import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis;
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.CfgPrinter;
+import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -136,7 +136,6 @@
private final StringOptimizer stringOptimizer;
private final StringBuilderOptimizer stringBuilderOptimizer;
private final IdempotentFunctionCallCanonicalizer idempotentFunctionCallCanonicalizer;
- private final InterfaceMethodRewriter interfaceMethodRewriter;
private final ClassInliner classInliner;
private final ClassStaticizer classStaticizer;
private final InternalOptions options;
@@ -220,7 +219,6 @@
// - invoke-special desugaring.
assert options.desugarState.isOn();
this.instructionDesugaring = CfInstructionDesugaringCollection.create(appView);
- this.interfaceMethodRewriter = null;
this.covariantReturnTypeAnnotationTransformer = null;
this.dynamicTypeOptimization = null;
this.classInliner = null;
@@ -246,10 +244,6 @@
appView.enableWholeProgramOptimizations()
? CfInstructionDesugaringCollection.empty()
: CfInstructionDesugaringCollection.create(appView);
- this.interfaceMethodRewriter =
- options.isInterfaceMethodDesugaringEnabled() && appView.enableWholeProgramOptimizations()
- ? new InterfaceMethodRewriter(appView, this)
- : null;
this.covariantReturnTypeAnnotationTransformer =
options.processCovariantReturnTypeAnnotations
? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory())
@@ -346,17 +340,10 @@
D8NestBasedAccessDesugaring::clearNestAttributes);
}
- private void staticizeClasses(
- OptimizationFeedback feedback, ExecutorService executorService, GraphLens applied)
+ private void staticizeClasses(OptimizationFeedback feedback, ExecutorService executorService)
throws ExecutionException {
if (classStaticizer != null) {
- classStaticizer.staticizeCandidates(feedback, executorService, applied);
- }
- }
-
- private void collectStaticizerCandidates(DexApplication application) {
- if (classStaticizer != null) {
- classStaticizer.collectCandidates(application);
+ classStaticizer.staticizeCandidates(feedback, executorService);
}
}
@@ -627,7 +614,6 @@
DexApplication application = appView.appInfo().app();
computeReachabilitySensitivity(application);
- collectStaticizerCandidates(application);
workaroundAbstractMethodOnNonAbstractClassVerificationBug(
executorService, simpleOptimizationFeedback);
@@ -639,7 +625,9 @@
printPhase("Primary optimization pass");
- // Setup the argument propagator for the primary optimization pass.
+ GraphLens graphLensForPrimaryOptimizationPass = appView.graphLens();
+
+ // Setup optimizations for the primary optimization pass.
appView.withArgumentPropagator(
argumentPropagator -> argumentPropagator.initializeCodeScanner(executorService, timing));
appView.withCallSiteOptimizationInfoPropagator(
@@ -649,16 +637,26 @@
optimization.abandonCallSitePropagationForPinnedMethodsAndOverrides(
executorService, timing);
});
+ ConsumerUtils.acceptIfNotNull(
+ enumUnboxer,
+ enumUnboxer ->
+ enumUnboxer.initializeEnumUnboxingCandidates(graphLensForPrimaryOptimizationPass));
+ ConsumerUtils.acceptIfNotNull(
+ classStaticizer,
+ classStaticizer ->
+ classStaticizer.prepareForPrimaryOptimizationPass(graphLensForPrimaryOptimizationPass));
+ ConsumerUtils.acceptIfNotNull(
+ inliner,
+ inliner -> inliner.initializeDoubleInlineCallers(graphLensForPrimaryOptimizationPass));
if (fieldAccessAnalysis != null) {
fieldAccessAnalysis.fieldAssignmentTracker().initialize();
}
// Process the application identifying outlining candidates.
- GraphLens initialGraphLensForIR = appView.graphLens();
- GraphLens graphLensForIR = initialGraphLensForIR;
OptimizationFeedbackDelayed feedback = delayedOptimizationFeedback;
- PostMethodProcessor.Builder postMethodProcessorBuilder = new PostMethodProcessor.Builder();
+ PostMethodProcessor.Builder postMethodProcessorBuilder =
+ new PostMethodProcessor.Builder(graphLensForPrimaryOptimizationPass);
{
timing.begin("Build primary method processor");
PrimaryMethodProcessor primaryMethodProcessor =
@@ -669,6 +667,7 @@
if (outliner != null) {
outliner.createOutlineMethodIdentifierGenerator();
}
+ assert appView.graphLens() == graphLensForPrimaryOptimizationPass;
primaryMethodProcessor.forEachMethod(
(method, methodProcessingContext) ->
processDesugaredMethod(
@@ -677,8 +676,8 @@
this::waveDone,
timing,
executorService);
+ assert appView.graphLens() == graphLensForPrimaryOptimizationPass;
timing.end();
- assert graphLensForIR == appView.graphLens();
}
// The field access info collection is not maintained during IR processing.
@@ -696,42 +695,54 @@
// Commit synthetics from the primary optimization pass.
commitPendingSyntheticItemsR8(appView);
+ // Post processing:
+ // 1) Second pass for methods whose collected call site information become more precise.
+ // 2) Second inlining pass for dealing with double inline callers.
+ printPhase("Post optimization pass");
+
// Analyze the data collected by the argument propagator, use the analysis result to update
// the parameter optimization infos, and rewrite the application.
appView.withArgumentPropagator(
argumentPropagator ->
argumentPropagator.tearDownCodeScanner(
postMethodProcessorBuilder, executorService, timing));
+ appView.withCallSiteOptimizationInfoPropagator(
+ callSiteOptimizationInfoPropagator ->
+ callSiteOptimizationInfoPropagator.enqueueMethodsForReprocessing(
+ postMethodProcessorBuilder));
if (libraryMethodOverrideAnalysis != null) {
libraryMethodOverrideAnalysis.finish();
}
- // Post processing:
- // 1) Second pass for methods whose collected call site information become more precise.
- // 2) Second inlining pass for dealing with double inline callers.
- printPhase("Post optimization pass");
- appView.withCallSiteOptimizationInfoPropagator(
- optimization ->
- postMethodProcessorBuilder.put(appView.callSiteOptimizationInfoPropagator()));
- if (inliner != null) {
- postMethodProcessorBuilder.put(inliner);
- }
+ ConsumerUtils.acceptIfNotNull(
+ inliner, inliner -> inliner.enqueueMethodsForReprocessing(postMethodProcessorBuilder));
+
if (!options.debug) {
new TrivialFieldAccessReprocessor(appView.withLiveness(), postMethodProcessorBuilder)
.run(executorService, feedback, timing);
}
+
if (enumUnboxer != null) {
enumUnboxer.unboxEnums(this, postMethodProcessorBuilder, executorService, feedback);
} else {
appView.setUnboxedEnums(EnumDataMap.empty());
}
+
+ GraphLens graphLensForSecondaryOptimizationPass = appView.graphLens();
+
+ ConsumerUtils.acceptIfNotNull(
+ classStaticizer,
+ classStaticizer ->
+ classStaticizer.prepareForSecondaryOptimizationPass(
+ graphLensForSecondaryOptimizationPass));
+
timing.begin("IR conversion phase 2");
- graphLensForIR = appView.graphLens();
PostMethodProcessor postMethodProcessor =
postMethodProcessorBuilder.build(appView, executorService, timing);
if (postMethodProcessor != null) {
assert !options.debug;
+ assert appView.graphLens() == graphLensForSecondaryOptimizationPass;
postMethodProcessor.forEachMethod(
(method, methodProcessingContext) ->
processDesugaredMethod(
@@ -739,7 +750,7 @@
feedback,
executorService);
feedback.updateVisibleOptimizationInfo();
- assert graphLensForIR == appView.graphLens();
+ assert appView.graphLens() == graphLensForSecondaryOptimizationPass;
}
timing.end();
@@ -756,7 +767,7 @@
if (!options.isGeneratingClassFiles()) {
printPhase("Class staticizer post processing");
// TODO(b/127694949): Adapt to PostOptimization.
- staticizeClasses(feedback, executorService, initialGraphLensForIR);
+ staticizeClasses(feedback, executorService);
feedback.updateVisibleOptimizationInfo();
// The class staticizer lens shall not be applied through lens code rewriting or it breaks
// the lambda merger.
@@ -1302,6 +1313,7 @@
.libraryMethodOptimizer()
.optimize(code, feedback, methodProcessor, methodProcessingContext);
timing.end();
+ previous = printMethod(code, "IR after class library method optimizer (SSA)", previous);
assert code.isConsistentSSA();
}
@@ -1312,6 +1324,7 @@
timing.begin("Devirtualize invoke interface");
devirtualizer.devirtualizeInvokeInterface(code);
timing.end();
+ previous = printMethod(code, "IR after devirtualizer (SSA)", previous);
}
assert code.verifyTypes(appView);
@@ -1388,12 +1401,14 @@
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",
@@ -1405,7 +1420,7 @@
deadCodeRemover.run(code, timing);
assert code.isConsistentSSA();
- previous = printMethod(code, "IR after lambda desugaring (SSA)", previous);
+ previous = printMethod(code, "IR after dead code removal (SSA)", previous);
assert code.verifyTypes(appView);
@@ -1591,7 +1606,7 @@
timing.end();
}
- if (appView.getKeepInfo().getMethodInfo(code.context()).isPinned(options)) {
+ if (appView.getKeepInfo(code.context()).isPinned(options)) {
return;
}
@@ -1713,8 +1728,7 @@
|| definition.getOptimizationInfo().isReachabilitySensitive()) {
return false;
}
- if (appView.appInfo().hasLiveness()
- && appView.appInfo().withLiveness().isPinned(method.getReference())) {
+ if (!appView.getKeepInfo(method).isInliningAllowed(options)) {
return false;
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index a8e5508..36c8dc6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -55,15 +55,22 @@
public static class Builder {
- private final LongLivedProgramMethodSetBuilder<?> methodsToReprocessBuilder =
- LongLivedProgramMethodSetBuilder.createForIdentitySet();
+ private final LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder;
- Builder() {}
+ Builder(GraphLens graphLensForPrimaryOptimizationPass) {
+ this.methodsToReprocessBuilder =
+ LongLivedProgramMethodSetBuilder.createForIdentitySet(
+ graphLensForPrimaryOptimizationPass);
+ }
public void add(ProgramMethod method) {
methodsToReprocessBuilder.add(method);
}
+ public LongLivedProgramMethodSetBuilder<ProgramMethodSet> getMethodsToReprocessBuilder() {
+ return methodsToReprocessBuilder;
+ }
+
public void put(ProgramMethodSet methodsToRevisit) {
methodsToRevisit.forEach(this::add);
}
@@ -72,15 +79,11 @@
put(postOptimization.methodsToRevisit());
}
- public void removePrunedMethods(Iterable<DexMethod> prunedMethod) {
- methodsToReprocessBuilder.removeAll(prunedMethod);
- }
-
// Some optimizations may change methods, creating new instances of the encoded methods with a
// new signature. The compiler needs to update the set of methods that must be reprocessed
// according to the graph lens.
- public void rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens applied) {
- methodsToReprocessBuilder.rewrittenWithLens(appView, applied);
+ public void rewrittenWithLens(AppView<AppInfoWithLiveness> appView) {
+ methodsToReprocessBuilder.rewrittenWithLens(appView);
}
PostMethodProcessor build(
@@ -103,8 +106,7 @@
// Nothing to revisit.
return null;
}
- ProgramMethodSet methodsToReprocess =
- methodsToReprocessBuilder.build(appView, appView.graphLens());
+ ProgramMethodSet methodsToReprocess = methodsToReprocessBuilder.build(appView);
CallGraph callGraph =
new PartialCallGraphBuilder(appView, methodsToReprocess).build(executorService, timing);
return new PostMethodProcessor(appView, callGraph);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 197ab34..64c4cd2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -88,11 +88,8 @@
@Override
public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
- return instruction.isInvoke() && methodIsBackport(instruction.asInvoke().getMethod());
- }
-
- public boolean methodIsBackport(DexMethod method) {
- return getMethodProviderOrNull(method) != null;
+ return instruction.isInvoke()
+ && getMethodProviderOrNull(instruction.asInvoke().getMethod()) != null;
}
public static List<DexMethod> generateListOfBackportedMethods(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
index e4a34c4..8f5178e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
@@ -6,14 +6,17 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClasspathClass;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.D8MethodProcessor;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
+import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringSyntheticHelper;
import com.android.tools.r8.ir.desugar.itf.InterfaceProcessingDesugaringEventConsumer;
import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.concurrent.ExecutionException;
+import java.util.function.BiConsumer;
/**
* Specialized Event consumer for desugaring finalization. During finalization, it is not possible
@@ -31,8 +34,10 @@
}
public static R8PostProcessingDesugaringEventConsumer createForR8(
- SyntheticAdditions additions, CfInstructionDesugaringCollection desugaring) {
- return new R8PostProcessingDesugaringEventConsumer(additions, desugaring);
+ SyntheticAdditions additions,
+ CfInstructionDesugaringCollection desugaring,
+ BiConsumer<DexProgramClass, DexType> missingClassConsumer) {
+ return new R8PostProcessingDesugaringEventConsumer(additions, desugaring, missingClassConsumer);
}
public abstract void finalizeDesugaring() throws ExecutionException;
@@ -60,6 +65,12 @@
}
@Override
+ public void warnMissingInterface(
+ DexProgramClass context, DexType missing, InterfaceDesugaringSyntheticHelper helper) {
+ helper.warnMissingInterface(context, context, missing);
+ }
+
+ @Override
public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) {
// Intentionally empty.
}
@@ -114,11 +125,21 @@
private final SyntheticAdditions additions;
private final CfInstructionDesugaringCollection desugaring;
+ private final BiConsumer<DexProgramClass, DexType> missingClassConsumer;
R8PostProcessingDesugaringEventConsumer(
- SyntheticAdditions additions, CfInstructionDesugaringCollection desugaring) {
+ SyntheticAdditions additions,
+ CfInstructionDesugaringCollection desugaring,
+ BiConsumer<DexProgramClass, DexType> missingClassConsumer) {
this.additions = additions;
this.desugaring = desugaring;
+ this.missingClassConsumer = missingClassConsumer;
+ }
+
+ @Override
+ public void warnMissingInterface(
+ DexProgramClass context, DexType missing, InterfaceDesugaringSyntheticHelper helper) {
+ missingClassConsumer.accept(context, missing);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
index 5760bd2..a18d9b9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
@@ -164,16 +164,18 @@
.setVirtualTarget(methodReference, methodHolder.isInterface())
.setCastResult();
DexEncodedMethod newVirtualMethod =
- new DexEncodedMethod(
- newMethod,
- newAccessFlags,
- methodDefinition.getGenericSignature(),
- methodDefinition
- .annotations()
- .keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation)),
- methodDefinition.parameterAnnotationsList.keepIf(Predicates.alwaysTrue()),
- forwardMethodBuilder.build(),
- true);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(newMethod)
+ .setAccessFlags(newAccessFlags)
+ .setGenericSignature(methodDefinition.getGenericSignature())
+ .setAnnotations(
+ methodDefinition
+ .annotations()
+ .keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation)))
+ .setParameterAnnotations(
+ methodDefinition.parameterAnnotationsList.keepIf(Predicates.alwaysTrue()))
+ .setCode(forwardMethodBuilder.build())
+ .build();
// Optimize to generate DexCode instead of CfCode.
ProgramMethod programMethod = new ProgramMethod(methodHolder, newVirtualMethod);
converter.optimizeSynthesizedMethod(programMethod);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index dd815a3..c7f5ec8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -26,12 +25,9 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexValueNull;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.Invoke.Type;
@@ -159,34 +155,30 @@
// Synthesize main method.
methods.add(
- new DexEncodedMethod(
- mainMethod,
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_FINAL, false),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- LambdaMainMethodSourceCode.build(this, mainMethod),
- true));
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(mainMethod)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_FINAL, false))
+ .setCode(LambdaMainMethodSourceCode.build(this, mainMethod))
+ .build());
// Synthesize bridge methods.
for (DexProto bridgeProto : descriptor.bridges) {
DexMethod bridgeMethod =
appView.dexItemFactory().createMethod(type, bridgeProto, descriptor.name);
methods.add(
- new DexEncodedMethod(
- bridgeMethod,
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC
- | Constants.ACC_FINAL
- | Constants.ACC_SYNTHETIC
- | Constants.ACC_BRIDGE,
- false),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- LambdaBridgeMethodSourceCode.build(this, bridgeMethod, mainMethod),
- true));
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(bridgeMethod)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC
+ | Constants.ACC_FINAL
+ | Constants.ACC_SYNTHETIC
+ | Constants.ACC_BRIDGE,
+ false))
+ .setCode(LambdaBridgeMethodSourceCode.build(this, bridgeMethod, mainMethod))
+ .build());
}
builder.setVirtualMethods(methods);
}
@@ -197,31 +189,27 @@
List<DexEncodedMethod> methods = new ArrayList<>(stateless ? 2 : 1);
// Constructor.
+ MethodAccessFlags accessFlags =
+ MethodAccessFlags.fromSharedAccessFlags(
+ (stateless ? Constants.ACC_PRIVATE : Constants.ACC_PUBLIC) | Constants.ACC_SYNTHETIC,
+ true);
methods.add(
- new DexEncodedMethod(
- constructor,
- MethodAccessFlags.fromSharedAccessFlags(
- (stateless ? Constants.ACC_PRIVATE : Constants.ACC_PUBLIC)
- | Constants.ACC_SYNTHETIC,
- true),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- LambdaConstructorSourceCode.build(this),
- true));
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(constructor)
+ .setAccessFlags(accessFlags)
+ .setCode(LambdaConstructorSourceCode.build(this))
+ .build());
// Class constructor for stateless lambda classes.
if (stateless) {
methods.add(
- new DexEncodedMethod(
- classConstructor,
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_SYNTHETIC | Constants.ACC_STATIC, true),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- LambdaClassConstructorSourceCode.build(this),
- true));
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(classConstructor)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_SYNTHETIC | Constants.ACC_STATIC, true))
+ .setCode(LambdaClassConstructorSourceCode.build(this))
+ .build());
feedback.classInitializerMayBePostponed(methods.get(1));
}
builder.setDirectMethods(methods);
@@ -233,19 +221,13 @@
int fieldCount = fieldTypes.length;
List<DexEncodedField> fields = new ArrayList<>(fieldCount);
for (int i = 0; i < fieldCount; i++) {
- boolean deprecated = false;
- boolean d8R8Synthesized = true;
fields.add(
- new DexEncodedField(
- getCaptureField(i),
- FieldAccessFlags.createPublicFinalSynthetic(),
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- null,
- deprecated,
- d8R8Synthesized,
+ DexEncodedField.syntheticBuilder()
+ .setField(getCaptureField(i))
+ .setAccessFlags(FieldAccessFlags.createPublicFinalSynthetic())
// The api level is computed when tracing.
- AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView)));
+ .setApiLevel(AndroidApiLevel.UNKNOWN)
+ .build());
}
builder.setInstanceFields(fields);
}
@@ -255,24 +237,20 @@
if (isStateless()) {
// Create instance field for stateless lambda.
assert this.lambdaField != null;
- boolean deprecated = false;
- boolean d8R8Synthesized = true;
builder.setStaticFields(
Collections.singletonList(
- new DexEncodedField(
- this.lambdaField,
- FieldAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC
- | Constants.ACC_FINAL
- | Constants.ACC_SYNTHETIC
- | Constants.ACC_STATIC),
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexValueNull.NULL,
- deprecated,
- d8R8Synthesized,
+ DexEncodedField.syntheticBuilder()
+ .setField(this.lambdaField)
+ .setAccessFlags(
+ FieldAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC
+ | Constants.ACC_FINAL
+ | Constants.ACC_SYNTHETIC
+ | Constants.ACC_STATIC))
+ .setStaticValue(DexValueNull.NULL)
// The api level is computed when tracing.
- AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView))));
+ .setApiLevel(AndroidApiLevel.UNKNOWN)
+ .build()));
}
}
@@ -579,14 +557,14 @@
// Always make the method public to provide access.
newAccessFlags.setPublic();
DexEncodedMethod newMethod =
- new DexEncodedMethod(
- callTarget,
- newAccessFlags,
- encodedMethod.getGenericSignature(),
- encodedMethod.annotations(),
- encodedMethod.parameterAnnotationsList,
- encodedMethod.getCode(),
- true);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(callTarget)
+ .setAccessFlags(newAccessFlags)
+ .setGenericSignature(encodedMethod.getGenericSignature())
+ .setAnnotations(encodedMethod.annotations())
+ .setParameterAnnotations(encodedMethod.parameterAnnotationsList)
+ .setCode(encodedMethod.getCode())
+ .build();
newMethod.copyMetadata(encodedMethod);
forcefullyMovedLambdaMethodConsumer.acceptForcefullyMovedLambdaMethod(
encodedMethod.getReference(), callTarget);
@@ -661,16 +639,15 @@
// its accessibility and make it virtual.
MethodAccessFlags newAccessFlags = encodedMethod.accessFlags.copy();
newAccessFlags.unsetPrivate();
- newAccessFlags.setPublic();
DexEncodedMethod newMethod =
- new DexEncodedMethod(
- callTarget,
- newAccessFlags,
- encodedMethod.getGenericSignature(),
- encodedMethod.annotations(),
- encodedMethod.parameterAnnotationsList,
- encodedMethod.getCode(),
- true);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(callTarget)
+ .setAccessFlags(newAccessFlags)
+ .setGenericSignature(encodedMethod.getGenericSignature())
+ .setAnnotations(encodedMethod.annotations())
+ .setParameterAnnotations(encodedMethod.parameterAnnotationsList)
+ .setCode(encodedMethod.getCode())
+ .build();
newMethod.copyMetadata(encodedMethod);
forcefullyMovedLambdaMethodConsumer.acceptForcefullyMovedLambdaMethod(
encodedMethod.getReference(), callTarget);
@@ -727,14 +704,11 @@
ProgramMethod accessorMethod =
new ProgramMethod(
accessorClass,
- new DexEncodedMethod(
- callTarget,
- MethodAccessFlags.createPublicStaticSynthetic(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- AccessorMethodSourceCode.build(LambdaClass.this, callTarget),
- true));
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(callTarget)
+ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+ .setCode(AccessorMethodSourceCode.build(LambdaClass.this, callTarget))
+ .build());
accessorClass.addDirectMethod(accessorMethod.getDefinition());
if (appView.options().isDesugaredLibraryCompilation()
|| appView.options().isGeneratingDex()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index bd2e603..22654d6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -124,28 +124,25 @@
private void synthesizeStaticFields(SyntheticProgramClassBuilder builder) {
builder.setStaticFields(
ImmutableList.of(
- DexEncodedField.builder()
+ DexEncodedField.syntheticBuilder()
.setField(this.initializedValueField)
.setAccessFlags(FieldAccessFlags.createPrivateStaticSynthetic())
.setApiLevel(AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView))
- .setD8R8Synthesized()
.build(),
- DexEncodedField.builder()
+ DexEncodedField.syntheticBuilder()
.setField(this.constantValueField)
.setAccessFlags(FieldAccessFlags.createPrivateStaticSynthetic())
.setApiLevel(AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView))
- .setD8R8Synthesized()
.build()));
}
private void synthesizeDirectMethods(SyntheticProgramClassBuilder builder) {
builder.setDirectMethods(
ImmutableList.of(
- DexEncodedMethod.builder()
+ DexEncodedMethod.syntheticBuilder()
.setMethod(getConstMethod)
.setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
.setCode(generateGetterCode(builder))
- .setD8R8Synthesized()
.setApiLevelForDefinition(AndroidApiLevel.S)
.setApiLevelForCode(AndroidApiLevel.S)
.build()));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
index be8ac84..50aa6b2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
@@ -26,7 +26,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
@@ -126,9 +125,7 @@
if (isAPIConversionSyntheticType(context.getHolderType(), wrapperSynthesizor, appView)) {
return false;
}
- CfInvoke invoke = instruction.asInvoke();
- return shouldRewriteInvoke(
- invoke.getMethod(), invoke.getInvokeType(context), invoke.isInterface(), context);
+ return shouldRewriteInvoke(instruction.asInvoke(), context);
}
static boolean isAPIConversionSyntheticType(
@@ -141,26 +138,20 @@
return type.descriptor.toString().startsWith(DESCRIPTOR_VIVIFIED_PREFIX);
}
- private DexClassAndMethod getMethodForDesugaring(
- DexMethod invokedMethod, boolean isInvokeSuper, boolean isInterface, ProgramMethod context) {
+ private DexClassAndMethod getMethodForDesugaring(CfInvoke invoke, ProgramMethod context) {
+ DexMethod invokedMethod = invoke.getMethod();
// TODO(b/191656218): Use lookupInvokeSpecial instead when this is all to Cf.
- return isInvokeSuper
+ return invoke.isInvokeSuper(context.getHolderType())
? appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context)
: appView
.appInfoForDesugaring()
- .resolveMethod(invokedMethod, isInterface)
+ .resolveMethod(invokedMethod, invoke.isInterface())
.getResolutionPair();
}
// TODO(b/191656218): Consider caching the result.
- private boolean shouldRewriteInvoke(
- DexMethod unresolvedInvokedMethod,
- Type invokeType,
- boolean isInterface,
- ProgramMethod context) {
- DexClassAndMethod invokedMethod =
- getMethodForDesugaring(
- unresolvedInvokedMethod, invokeType == Type.SUPER, isInterface, context);
+ private boolean shouldRewriteInvoke(CfInvoke invoke, ProgramMethod context) {
+ DexClassAndMethod invokedMethod = getMethodForDesugaring(invoke, context);
if (invokedMethod == null) {
// Implies a resolution/look-up failure, we do not convert to keep the runtime error.
return false;
@@ -176,7 +167,7 @@
if (isEmulatedInterfaceOverride(invokedMethod)) {
return false;
}
- if (isAlreadyDesugared(unresolvedInvokedMethod, invokeType, isInterface, context)) {
+ if (isAlreadyDesugared(invoke, context)) {
return false;
}
return appView.rewritePrefix.hasRewrittenTypeInSignature(invokedMethod.getProto(), appView);
@@ -203,22 +194,16 @@
.containsKey(interfaceResult.getHolderType());
}
- private boolean isAlreadyDesugared(
- DexMethod unresolvedInvokedMethod,
- Type invokeType,
- boolean isInterface,
- ProgramMethod context) {
+ private boolean isAlreadyDesugared(CfInvoke invoke, ProgramMethod context) {
if (interfaceMethodRewriter != null
- && interfaceMethodRewriter.needsRewriting(unresolvedInvokedMethod, invokeType, context)) {
+ && interfaceMethodRewriter.needsDesugaring(invoke, context)) {
return true;
}
- if (retargeter != null
- && retargeter.hasNewInvokeTarget(
- unresolvedInvokedMethod, isInterface, invokeType == Type.SUPER, context)) {
+ if (retargeter != null && retargeter.needsDesugaring(invoke, context)) {
return true;
}
if (backportedMethodRewriter != null
- && backportedMethodRewriter.methodIsBackport(unresolvedInvokedMethod)) {
+ && backportedMethodRewriter.needsDesugaring(invoke, context)) {
return true;
}
return false;
@@ -378,8 +363,7 @@
if (invoke.getMethod().isInstanceInitializer(appView.dexItemFactory())) {
return false;
}
- DexClassAndMethod methodForDesugaring =
- getMethodForDesugaring(invoke.getMethod(), false, invoke.isInterface(), context);
+ DexClassAndMethod methodForDesugaring = getMethodForDesugaring(invoke, context);
assert methodForDesugaring != null;
return methodForDesugaring.getAccessFlags().isPublic();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
index 8a59f14..73d7f8f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
@@ -19,11 +19,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
@@ -91,34 +86,6 @@
return computeNewInvokeTarget(instruction, context).hasNewInvokeTarget();
}
- @Deprecated // Use Cf to Cf desugaring instead.
- public void desugar(IRCode code) {
- if (retargetLibraryMember.isEmpty()) {
- return;
- }
-
- InstructionListIterator iterator = code.instructionListIterator();
- while (iterator.hasNext()) {
- Instruction instruction = iterator.next();
- if (!instruction.isInvokeMethod()) {
- continue;
- }
-
- InvokeMethod invoke = instruction.asInvokeMethod();
- DexMethod invokedMethod = invoke.getInvokedMethod();
- boolean isInterface = invoke.getInterfaceBit();
-
- InvokeRetargetingResult invokeRetargetingResult =
- computeNewInvokeTarget(
- invokedMethod, isInterface, invoke.isInvokeSuper(), code.context());
- if (invokeRetargetingResult.hasNewInvokeTarget()) {
- DexMethod newInvokeTarget = invokeRetargetingResult.getNewInvokeTarget(null);
- iterator.replaceCurrentInstruction(
- new InvokeStatic(newInvokeTarget, invoke.outValue(), invoke.inValues()));
- }
- }
- }
-
static class InvokeRetargetingResult {
static InvokeRetargetingResult NO_REWRITING =
@@ -154,32 +121,20 @@
}
}
- public boolean hasNewInvokeTarget(
- DexMethod invokedMethod, boolean isInterface, boolean isInvokeSuper, ProgramMethod context) {
- return computeNewInvokeTarget(invokedMethod, isInterface, isInvokeSuper, context)
- .hasNewInvokeTarget();
- }
-
private InvokeRetargetingResult computeNewInvokeTarget(
CfInstruction instruction, ProgramMethod context) {
if (retargetLibraryMember.isEmpty() || !instruction.isInvoke()) {
return NO_REWRITING;
}
CfInvoke cfInvoke = instruction.asInvoke();
- return computeNewInvokeTarget(
- cfInvoke.getMethod(),
- cfInvoke.isInterface(),
- cfInvoke.isInvokeSuper(context.getHolderType()),
- context);
- }
-
- private InvokeRetargetingResult computeNewInvokeTarget(
- DexMethod invokedMethod, boolean isInterface, boolean isInvokeSuper, ProgramMethod context) {
- InvokeRetargetingResult retarget = computeRetargetedMethod(invokedMethod, isInterface);
+ DexMethod invokedMethod = cfInvoke.getMethod();
+ InvokeRetargetingResult retarget =
+ computeRetargetedMethod(invokedMethod, cfInvoke.isInterface());
if (!retarget.hasNewInvokeTarget()) {
return NO_REWRITING;
}
- if (isInvokeSuper && matchesNonFinalHolderRewrite(invokedMethod)) {
+ if (cfInvoke.isInvokeSuper(context.getHolderType())
+ && matchesNonFinalHolderRewrite(invokedMethod)) {
DexClassAndMethod superTarget =
appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
// Final methods can be rewritten as a normal invoke.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterLibraryTypeSynthesizor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterLibraryTypeSynthesizor.java
index 8c5a747..9e50613 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterLibraryTypeSynthesizor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterLibraryTypeSynthesizor.java
@@ -22,12 +22,10 @@
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.NestHostClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.StringDiagnostic;
import java.util.Comparator;
@@ -140,15 +138,13 @@
newClass,
ignore -> new TreeSet<>(Comparator.comparing(DexEncodedMethod::getReference)))
.add(
- new DexEncodedMethod(
- retargetMethod,
- MethodAccessFlags.fromCfAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_STATIC, false),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- null,
- true));
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(retargetMethod)
+ .setAccessFlags(
+ MethodAccessFlags.fromCfAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC, false))
+ .setCode(null)
+ .build());
}
});
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
index aa69845..9bc1a8e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClasspathClass;
import com.android.tools.r8.graph.DexEncodedField;
@@ -21,10 +20,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaring;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
@@ -561,14 +557,11 @@
// TODO(b/146114533): Fix inlining in synthetic methods and remove unsetBridge.
newFlags.unsetBridge();
newFlags.setSynthetic();
- return new DexEncodedMethod(
- methodToInstall,
- newFlags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- true);
+ return DexEncodedMethod.syntheticBuilder()
+ .setMethod(methodToInstall)
+ .setAccessFlags(newFlags)
+ .setCode(code)
+ .build();
}
private List<DexEncodedMethod> allImplementedMethods(DexClass clazz) {
@@ -624,8 +617,10 @@
// Field is package private to be accessible from convert methods without a getter.
FieldAccessFlags fieldAccessFlags =
FieldAccessFlags.fromCfAccessFlags(Constants.ACC_FINAL | Constants.ACC_SYNTHETIC);
- return new DexEncodedField(
- field, fieldAccessFlags, FieldTypeSignature.noSignature(), DexAnnotationSet.empty(), null);
+ return DexEncodedField.syntheticBuilder()
+ .setField(field)
+ .setAccessFlags(fieldAccessFlags)
+ .build();
}
// Program wrappers are harder to deal with than classpath wrapper because generating a method's
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 8661587..2b8e3c7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -25,11 +24,9 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GenericSignature;
import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.LibraryMethod;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.utils.BooleanBox;
@@ -51,6 +48,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -295,10 +293,15 @@
final DexClass directSubClass;
final DexProgramClass closestProgramSubClass;
+ final BiConsumer<DexProgramClass, DexType> reportMissingTypeCallback;
- public ReportingContext(DexClass directSubClass, DexProgramClass closestProgramSubClass) {
+ public ReportingContext(
+ DexClass directSubClass,
+ DexProgramClass closestProgramSubClass,
+ BiConsumer<DexProgramClass, DexType> reportMissingTypeCallback) {
this.directSubClass = directSubClass;
this.closestProgramSubClass = closestProgramSubClass;
+ this.reportMissingTypeCallback = reportMissingTypeCallback;
}
ReportingContext forClass(DexClass directSubClass) {
@@ -306,15 +309,16 @@
directSubClass,
directSubClass.isProgramClass()
? directSubClass.asProgramClass()
- : closestProgramSubClass);
+ : closestProgramSubClass,
+ reportMissingTypeCallback);
}
public DexClass definitionFor(DexType type, AppView<?> appView) {
return appView.appInfo().definitionForDesugarDependency(directSubClass, type);
}
- public void reportMissingType(DexType missingType, InterfaceDesugaringSyntheticHelper helper) {
- helper.warnMissingInterface(closestProgramSubClass, closestProgramSubClass, missingType);
+ public void reportMissingType(DexType missingType) {
+ reportMissingTypeCallback.accept(closestProgramSubClass, missingType);
}
}
@@ -324,7 +328,7 @@
static final LibraryReportingContext LIBRARY_CONTEXT = new LibraryReportingContext();
LibraryReportingContext() {
- super(null, null);
+ super(null, null, null);
}
@Override
@@ -338,7 +342,7 @@
}
@Override
- public void reportMissingType(DexType missingType, InterfaceDesugaringSyntheticHelper helper) {
+ public void reportMissingType(DexType missingType) {
// Ignore missing types in the library.
}
}
@@ -400,7 +404,12 @@
public void process(
DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
if (!clazz.isInterface()) {
- visitClassInfo(clazz, new ReportingContext(clazz, clazz));
+ visitClassInfo(
+ clazz,
+ new ReportingContext(
+ clazz,
+ clazz,
+ (context, missing) -> eventConsumer.warnMissingInterface(context, missing, helper)));
}
}
@@ -788,14 +797,12 @@
MethodAccessFlags accessFlags = MethodAccessFlags.builder().setPublic().build();
DexMethod newMethod = method.withHolder(clazz.getType(), dexItemFactory);
DexEncodedMethod newEncodedMethod =
- new DexEncodedMethod(
- newMethod,
- accessFlags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- createExceptionThrowingCfCode(newMethod, accessFlags, errorType, dexItemFactory),
- true);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(newMethod)
+ .setAccessFlags(accessFlags)
+ .setCode(
+ createExceptionThrowingCfCode(newMethod, accessFlags, errorType, dexItemFactory))
+ .build();
addSyntheticMethod(clazz.asProgramClass(), newEncodedMethod);
}
@@ -864,7 +871,7 @@
}
DexClass clazz = context.definitionFor(type, appView);
if (clazz == null) {
- context.reportMissingType(type, helper);
+ context.reportMissingType(type);
return null;
}
return clazz;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index 9ee3606..a2a2bf9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexClasspathClass;
@@ -28,7 +27,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexValueInt;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.InvalidCode;
import com.android.tools.r8.graph.MethodAccessFlags;
@@ -456,12 +454,12 @@
dexItemFactory.intType,
"$desugar$clinit",
candidate -> iface.lookupField(candidate) == null);
- return new DexEncodedField(
- clinitFieldReference,
- FieldAccessFlags.builder().setPackagePrivate().setStatic().setSynthetic().build(),
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexValueInt.DEFAULT);
+ return DexEncodedField.syntheticBuilder()
+ .setField(clinitFieldReference)
+ .setAccessFlags(
+ FieldAccessFlags.builder().setPackagePrivate().setStatic().setSynthetic().build())
+ .setStaticValue(DexValueInt.DEFAULT)
+ .build();
}
private void createCompanionClassInitializer(
@@ -526,7 +524,8 @@
return shouldIgnoreFromReportsPredicate.test(missing);
}
- void warnMissingInterface(DexClass classToDesugar, DexClass implementing, DexType missing) {
+ public void warnMissingInterface(
+ DexClass classToDesugar, DexClass implementing, DexType missing) {
// We use contains() on non hashed collection, but we know it's a 8 cases collection.
// j$ interfaces won't be missing, they are in the desugared library.
if (shouldIgnoreFromReports(missing)) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 77f2c98..7dc9de3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -243,7 +243,7 @@
+ InterfaceDesugaringSyntheticHelper.COMPANION_CLASS_NAME_SUFFIX)));
}
- public boolean needsRewriting(DexMethod method, Type invokeType, ProgramMethod context) {
+ private boolean needsRewriting(DexMethod method, Type invokeType, ProgramMethod context) {
return !isSyntheticMethodThatShouldNotBeDoubleProcessed(context)
&& invokeNeedsRewriting(method, invokeType);
}
@@ -273,15 +273,14 @@
return true;
}
- private boolean isAlreadyRewritten(
- DexMethod method, boolean itfBit, boolean isSuper, ProgramMethod context) {
-
+ private boolean isAlreadyDesugared(CfInvoke invoke, ProgramMethod context) {
// In Cf to Cf it is forbidden to desugar twice the same instruction, if the backported
// method rewriter or the desugared library retargeter already desugar the instruction, they
// take precedence and nothing has to be done here.
- return (backportedMethodRewriter != null && backportedMethodRewriter.methodIsBackport(method))
+ return (backportedMethodRewriter != null
+ && backportedMethodRewriter.needsDesugaring(invoke, context))
|| (desugaredLibraryRetargeter != null
- && desugaredLibraryRetargeter.hasNewInvokeTarget(method, itfBit, isSuper, context));
+ && desugaredLibraryRetargeter.needsDesugaring(invoke, context));
}
@Override
@@ -310,11 +309,7 @@
}
if (instruction.isInvoke()) {
CfInvoke cfInvoke = instruction.asInvoke();
- if (isAlreadyRewritten(
- cfInvoke.getMethod(),
- cfInvoke.isInterface(),
- cfInvoke.isInvokeSuper(context.getHolderType()),
- context)) {
+ if (isAlreadyDesugared(cfInvoke, context)) {
continue;
}
if (cfInvoke.isInvokeStatic()) {
@@ -385,11 +380,7 @@
public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
if (instruction.isInvoke()) {
CfInvoke cfInvoke = instruction.asInvoke();
- if (isAlreadyRewritten(
- cfInvoke.getMethod(),
- cfInvoke.isInterface(),
- cfInvoke.isInvokeSuper(context.getHolderType()),
- context)) {
+ if (isAlreadyDesugared(cfInvoke, context)) {
return false;
}
return needsRewriting(cfInvoke.getMethod(), cfInvoke.getInvokeType(context), context);
@@ -410,11 +401,7 @@
return null;
}
CfInvoke invoke = instruction.asInvoke();
- if (isAlreadyRewritten(
- invoke.getMethod(),
- invoke.isInterface(),
- invoke.isInvokeSuper(context.getHolderType()),
- context)) {
+ if (isAlreadyDesugared(invoke, context)) {
return null;
}
@@ -461,8 +448,7 @@
};
// TODO(b/192439456): Make a test to prove resolution is needed here and fix it.
return rewriteInvokeStatic(
- invoke.getMethod(),
- invoke.isInterface(),
+ invoke,
methodProcessingContext,
context,
staticOutliningMethodConsumer,
@@ -485,11 +471,7 @@
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext) {
- if (isAlreadyRewritten(
- invoke.getMethod(),
- invoke.isInterface(),
- invoke.isInvokeSuper(context.getHolderType()),
- context)) {
+ if (isAlreadyDesugared(invoke, context)) {
return null;
}
@@ -672,14 +654,15 @@
}
private Collection<CfInstruction> rewriteInvokeStatic(
- DexMethod invokedMethod,
- boolean interfaceBit,
+ CfInvoke invoke,
MethodProcessingContext methodProcessingContext,
ProgramMethod context,
Consumer<ProgramMethod> staticOutliningMethodConsumer,
Function<DexMethod, Collection<CfInstruction>> rewriteInvoke,
Function<SingleResolutionResult, Collection<CfInstruction>> rewriteToThrow,
CfInstructionDesugaringEventConsumer eventConsumer) {
+ DexMethod invokedMethod = invoke.getMethod();
+ boolean interfaceBit = invoke.isInterface();
if (appView.getSyntheticItems().isPendingSynthetic(invokedMethod.holder)) {
// We did not create this code yet, but it will not require rewriting.
return null;
@@ -727,7 +710,7 @@
// to outline again the invoke-static. Just do nothing instead.
return null;
}
- if (isAlreadyRewritten(invokedMethod, interfaceBit, false, context)) {
+ if (isAlreadyDesugared(invoke, context)) {
return null;
}
ProgramMethod newProgramMethod =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
index e16f254..49d843d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.DexClasspathClass;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
// TODO(b/183998768): Consider forcing the processing of interface methods in D8 akin to R8.
@@ -18,4 +19,7 @@
void acceptEmulatedInterfaceMarkerInterface(
DexProgramClass clazz, DexClasspathClass newInterface);
+
+ void warnMissingInterface(
+ DexProgramClass context, DexType missing, InterfaceDesugaringSyntheticHelper helper);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
index 8814c2e..b81ea84 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
@@ -21,7 +21,7 @@
assert field.getAccessFlags().isPrivate();
return new ProgramMethod(
field.getHolder(),
- DexEncodedMethod.builder()
+ DexEncodedMethod.syntheticBuilder()
.setAccessFlags(
MethodAccessFlags.builder()
.setBridge()
@@ -37,7 +37,6 @@
.setSourceMethod(bridgeMethodReference)
.build())
.setMethod(bridgeMethodReference)
- .setD8R8Synthesized()
.setApiLevelForDefinition(field.getDefinition().getApiLevel())
.setApiLevelForCode(field.getDefinition().getApiLevel())
.build());
@@ -51,7 +50,7 @@
assert !method.getHolder().isInterface();
return new ProgramMethod(
method.getHolder(),
- DexEncodedMethod.builder()
+ DexEncodedMethod.syntheticBuilder()
// Not setting the 'bridge' flag as this fails verification.
.setAccessFlags(MethodAccessFlags.builder().setConstructor().setSynthetic().build())
.setCode(
@@ -60,7 +59,6 @@
.setConstructorTarget(method.getReference())
.build())
.setMethod(bridgeMethodReference)
- .setD8R8Synthesized()
.setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
.setApiLevelForCode(method.getDefinition().getApiLevelForCode())
.build());
@@ -74,7 +72,7 @@
boolean isInterface = method.getHolder().isInterface();
return new ProgramMethod(
method.getHolder(),
- DexEncodedMethod.builder()
+ DexEncodedMethod.syntheticBuilder()
.setAccessFlags(
MethodAccessFlags.builder()
.setBridge()
@@ -93,7 +91,6 @@
.setMethod(bridgeMethodReference)
.setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
.setApiLevelForCode(method.getDefinition().getApiLevelForDefinition())
- .setD8R8Synthesized()
.build());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
index 7c26d30..627f8af 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
@@ -20,7 +20,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -35,9 +34,7 @@
import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.DexValue.DexValueType;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaring;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
@@ -289,14 +286,11 @@
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_SYNTHETIC | Constants.ACC_PRIVATE, false);
DexEncodedMethod encodedMethod =
- new DexEncodedMethod(
- method,
- methodAccessFlags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- null,
- true);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(method)
+ .setAccessFlags(methodAccessFlags)
+ .setCode(null)
+ .build();
encodedMethod.setCode(provider.generateCfCode(), appView);
return new ProgramMethod(clazz, encodedMethod);
}
@@ -589,14 +583,11 @@
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_SYNTHETIC | Constants.ACC_PROTECTED, true);
DexEncodedMethod init =
- new DexEncodedMethod(
- factory.recordMembers.init,
- methodAccessFlags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- null,
- true);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(factory.recordMembers.init)
+ .setAccessFlags(methodAccessFlags)
+ .setCode(null)
+ .build();
init.setCode(
new CallObjectInitCfCodeProvider(appView, factory.recordTagType).generateCfCode(), appView);
return init;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
index ce0646d..d39f509 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.LookupResult;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
@@ -19,7 +20,7 @@
import com.android.tools.r8.ir.code.InvokeCustom;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
-import com.android.tools.r8.ir.conversion.PostOptimization;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
import com.android.tools.r8.logging.Log;
@@ -31,6 +32,7 @@
import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import java.util.Set;
@@ -38,7 +40,7 @@
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
-public class CallSiteOptimizationInfoPropagator implements PostOptimization {
+public class CallSiteOptimizationInfoPropagator {
// TODO(b/139246447): should we revisit new targets over and over again?
// Maybe piggy-back on MethodProcessor's wave/batch processing?
@@ -61,16 +63,17 @@
private final AppView<AppInfoWithLiveness> appView;
private final InternalOptions options;
private final CallSiteOptimizationOptions optimizationOptions;
- private ProgramMethodSet revisitedMethods = null;
private Mode mode = Mode.COLLECT;
+ private ProgramMethodSet revisitedMethodsForTesting = null;
+
public CallSiteOptimizationInfoPropagator(AppView<AppInfoWithLiveness> appView) {
assert appView.enableWholeProgramOptimizations();
this.appView = appView;
this.options = appView.options();
this.optimizationOptions = appView.options().callSiteOptimizationOptions();
if (Log.isLoggingEnabledFor(CallSiteOptimizationInfoPropagator.class)) {
- revisitedMethods = ProgramMethodSet.create();
+ revisitedMethodsForTesting = ProgramMethodSet.create();
}
}
@@ -80,9 +83,9 @@
public void logResults() {
assert Log.ENABLED;
- if (revisitedMethods != null) {
- Log.info(getClass(), "# of methods to revisit: %s", revisitedMethods.size());
- for (ProgramMethod m : revisitedMethods) {
+ if (revisitedMethodsForTesting != null) {
+ Log.info(getClass(), "# of methods to revisit: %s", revisitedMethodsForTesting.size());
+ for (ProgramMethod m : revisitedMethodsForTesting) {
Log.info(
getClass(),
"%s: %s",
@@ -379,10 +382,19 @@
return callSiteOptimizationInfo;
}
- @Override
- public ProgramMethodSet methodsToRevisit() {
+ public void enqueueMethodsForReprocessing(
+ PostMethodProcessor.Builder postMethodProcessorBuilder) {
+ postMethodProcessorBuilder
+ .getMethodsToReprocessBuilder()
+ .rewrittenWithLens(appView.graphLens())
+ .merge(methodsToRevisit());
+ }
+
+ private LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToRevisit() {
mode = Mode.REVISIT;
- ProgramMethodSet targetsToRevisit = ProgramMethodSet.create();
+ GraphLens currentGraphLens = appView.graphLens();
+ LongLivedProgramMethodSetBuilder<ProgramMethodSet> builder =
+ LongLivedProgramMethodSetBuilder.createForIdentitySet(currentGraphLens);
for (DexProgramClass clazz : appView.appInfo().classes()) {
clazz.forEachProgramMethodMatching(
definition -> {
@@ -398,14 +410,14 @@
return callSiteOptimizationInfo.hasUsefulOptimizationInfo(appView, definition);
},
method -> {
- targetsToRevisit.add(method);
+ builder.add(method, currentGraphLens);
appView.options().testing.callSiteOptimizationInfoInspector.accept(method);
});
}
- if (revisitedMethods != null) {
- revisitedMethods.addAll(targetsToRevisit);
+ if (revisitedMethodsForTesting != null) {
+ revisitedMethodsForTesting.addAll(builder.build(appView));
}
- return targetsToRevisit;
+ return builder;
}
private synchronized boolean verifyAllProgramDispatchTargetsHaveBeenAbandoned(
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 fdc9208..7bf0e38 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
@@ -48,7 +48,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.LensCodeRewriter;
import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.conversion.PostOptimization;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.ir.optimize.inliner.DefaultInliningReasonStrategy;
@@ -64,6 +64,7 @@
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -77,7 +78,7 @@
import java.util.Map;
import java.util.Set;
-public class Inliner implements PostOptimization {
+public class Inliner {
protected final AppView<AppInfoWithLiveness> appView;
private final Set<DexMethod> extraNeverInlineMethods;
@@ -86,7 +87,7 @@
// State for inlining methods which are known to be called twice.
private boolean applyDoubleInlining = false;
- private final ProgramMethodSet doubleInlineCallers = ProgramMethodSet.create();
+ private LongLivedProgramMethodSetBuilder<ProgramMethodSet> doubleInlineCallers;
private final ProgramMethodSet doubleInlineSelectedTargets = ProgramMethodSet.create();
private final Map<DexEncodedMethod, ProgramMethod> doubleInlineeCandidates =
new IdentityHashMap<>();
@@ -117,7 +118,7 @@
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod singleTargetReference = singleTarget.getReference();
- if (appInfo.isPinned(singleTargetReference)) {
+ if (!appView.getKeepInfo(singleTarget).isInliningAllowed(appView.options())) {
whyAreYouNotInliningReporter.reportPinned();
return true;
}
@@ -226,9 +227,10 @@
if (doubleInlineeCandidates.containsKey(target.getDefinition())) {
// Both calls can be inlined.
+ GraphLens currentGraphLens = appView.graphLens();
ProgramMethod doubleInlineeCandidate = doubleInlineeCandidates.get(target.getDefinition());
- doubleInlineCallers.add(doubleInlineeCandidate);
- doubleInlineCallers.add(method);
+ doubleInlineCallers.add(doubleInlineeCandidate, currentGraphLens);
+ doubleInlineCallers.add(method, currentGraphLens);
doubleInlineSelectedTargets.add(target);
} else {
// First call can be inlined.
@@ -236,10 +238,20 @@
}
}
- @Override
- public ProgramMethodSet methodsToRevisit() {
+ public void initializeDoubleInlineCallers(GraphLens graphLensForPrimaryOptimizationPass) {
+ assert appView.graphLens() == graphLensForPrimaryOptimizationPass;
+ doubleInlineCallers =
+ LongLivedProgramMethodSetBuilder.createForIdentitySet(graphLensForPrimaryOptimizationPass);
+ }
+
+ public void enqueueMethodsForReprocessing(
+ PostMethodProcessor.Builder postMethodProcessorBuilder) {
+ // The double inline callers are always rewritten up until the graph lens of the primary
+ // optimization pass, so we can safely merge them into the methods to reprocess (which may be
+ // rewritten with a newer graph lens).
+ postMethodProcessorBuilder.getMethodsToReprocessBuilder().merge(doubleInlineCallers);
+ doubleInlineCallers = null;
applyDoubleInlining = true;
- return doubleInlineCallers;
}
/**
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 df30aac..b2e8366 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
@@ -310,7 +310,10 @@
DexType type = proto.parameters.values[i];
if (type.isAlwaysNull(appView)) {
RemovedArgumentInfo removedArg =
- RemovedArgumentInfo.builder().setIsAlwaysNull().setType(type).build();
+ RemovedArgumentInfo.builder()
+ .setSingleValue(appView.abstractValueFactory().createNullValue())
+ .setType(type)
+ .build();
argInfosBuilder.addArgumentInfo(i + offset, removedArg);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index 2e74bb2..705ce93 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndField;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMember;
@@ -101,6 +102,7 @@
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.android.tools.r8.utils.collections.ProgramMethodMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.HashMultiset;
@@ -135,18 +137,20 @@
private final DexItemFactory factory;
// Map the enum candidates with their dependencies, i.e., the methods to reprocess for the given
// enum if the optimization eventually decides to unbox it.
- private final EnumUnboxingCandidateInfoCollection enumUnboxingCandidatesInfo;
+ private EnumUnboxingCandidateInfoCollection enumUnboxingCandidatesInfo;
private final Set<DexProgramClass> candidatesToRemoveInWave = Sets.newConcurrentHashSet();
private final Map<DexType, EnumStaticFieldValues> staticFieldValuesMap =
new ConcurrentHashMap<>();
- private final ProgramMethodSet methodsDependingOnLibraryModelisation =
- ProgramMethodSet.createConcurrent();
+
+ // Methods depending on library modelisation need to be reprocessed so they are peephole
+ // optimized.
+ private LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsDependingOnLibraryModelisation;
// Map from checkNotNull() methods to the enums that use the given method.
private final ProgramMethodMap<Set<DexProgramClass>> checkNotNullMethods =
ProgramMethodMap.createConcurrent();
- private final DexEncodedField ordinalField;
+ private final DexClassAndField ordinalField;
private EnumUnboxingRewriter enumUnboxerRewriter;
@@ -164,21 +168,18 @@
debugLogs = null;
}
assert !appView.options().debug;
- enumUnboxingCandidatesInfo = new EnumUnboxingCandidateAnalysis(appView, this).findCandidates();
-
ordinalField =
- appView.appInfo().resolveField(factory.enumMembers.ordinalField).getResolvedField();
- if (ordinalField == null) {
- // This can happen when compiling for non standard libraries, in that case, this effectively
- // disables the enum unboxer.
- enumUnboxingCandidatesInfo.clear();
- }
+ appView.appInfo().resolveField(factory.enumMembers.ordinalField).getResolutionPair();
}
public static int ordinalToUnboxedInt(int ordinal) {
return ordinal + 1;
}
+ public DexClassAndField getOrdinalField() {
+ return ordinalField;
+ }
+
public void updateEnumUnboxingCandidatesInfo() {
for (DexProgramClass candidate : candidatesToRemoveInWave) {
enumUnboxingCandidatesInfo.removeCandidate(candidate);
@@ -203,7 +204,7 @@
}
private void markMethodDependsOnLibraryModelisation(ProgramMethod method) {
- methodsDependingOnLibraryModelisation.add(method);
+ methodsDependingOnLibraryModelisation.add(method, appView.graphLens());
}
private DexProgramClass getEnumUnboxingCandidateOrNull(TypeElement lattice) {
@@ -298,7 +299,7 @@
enumUnboxingCandidatesInfo.addMethodDependency(eligibleEnum, code.context());
}
}
- if (methodsDependingOnLibraryModelisation.contains(code.context())) {
+ if (methodsDependingOnLibraryModelisation.contains(code.context(), appView.graphLens())) {
conversionOptions.disablePeepholeOptimizations();
}
}
@@ -555,6 +556,16 @@
return result;
}
+ public void initializeEnumUnboxingCandidates(GraphLens graphLensForPrimaryOptimizationPass) {
+ assert enumUnboxingCandidatesInfo == null;
+ enumUnboxingCandidatesInfo =
+ new EnumUnboxingCandidateAnalysis(appView, this)
+ .findCandidates(graphLensForPrimaryOptimizationPass);
+ methodsDependingOnLibraryModelisation =
+ LongLivedProgramMethodSetBuilder.createConcurrentForIdentitySet(
+ graphLensForPrimaryOptimizationPass);
+ }
+
public void unboxEnums(
IRConverter converter,
PostMethodProcessor.Builder postBuilder,
@@ -577,7 +588,8 @@
ImmutableSet<DexType> enumsToUnbox = enumUnboxingCandidatesInfo.candidates();
ImmutableSet<DexProgramClass> enumClassesToUnbox =
enumUnboxingCandidatesInfo.candidateClasses();
- ProgramMethodSet dependencies = enumUnboxingCandidatesInfo.allMethodDependencies();
+ LongLivedProgramMethodSetBuilder<ProgramMethodSet> dependencies =
+ enumUnboxingCandidatesInfo.allMethodDependencies();
enumUnboxingCandidatesInfo.clear();
// Update keep info on any of the enum methods of the removed classes.
updateKeepInfo(enumsToUnbox);
@@ -587,11 +599,32 @@
.synthesizeEnumUnboxingUtilityClasses(enumClassesToUnbox, enumDataMap)
.build(converter, executorService);
+ // Fixup the application.
EnumUnboxingTreeFixer.Result treeFixerResult =
new EnumUnboxingTreeFixer(
appView, checkNotNullMethods, enumDataMap, enumClassesToUnbox, utilityClasses)
.fixupTypeReferences(converter, executorService);
EnumUnboxingLens enumUnboxingLens = treeFixerResult.getLens();
+ appView.setUnboxedEnums(enumDataMap);
+
+ // Update the graph lens.
+ appView.rewriteWithLens(enumUnboxingLens);
+
+ // Enqueue the (lens rewritten) methods that require reprocessing.
+ //
+ // Note that the reprocessing set must be rewritten to the new enum unboxing lens before pruning
+ // the builders with the methods removed by the tree fixer (since these methods references are
+ // already fully lens rewritten).
+ postBuilder
+ .getMethodsToReprocessBuilder()
+ .rewrittenWithLens(appView)
+ .merge(dependencies)
+ .merge(methodsDependingOnLibraryModelisation)
+ .removeAll(treeFixerResult.getPrunedItems().getRemovedMethods());
+ methodsDependingOnLibraryModelisation.clear();
+
+ updateOptimizationInfos(executorService, feedback, treeFixerResult.getPrunedItems());
+
enumUnboxerRewriter =
new EnumUnboxingRewriter(
appView,
@@ -600,17 +633,6 @@
enumUnboxingLens,
enumDataMap,
utilityClasses);
- appView.setUnboxedEnums(enumDataMap);
- GraphLens previousLens = appView.graphLens();
- appView.rewriteWithLens(enumUnboxingLens);
- updateOptimizationInfos(executorService, feedback, treeFixerResult.getPrunedItems());
- postBuilder.put(dependencies);
- // Methods depending on library modelisation need to be reprocessed so they are peephole
- // optimized.
- postBuilder.put(methodsDependingOnLibraryModelisation);
- methodsDependingOnLibraryModelisation.clear();
- postBuilder.removePrunedMethods(treeFixerResult.getPrunedItems().getRemovedMethods());
- postBuilder.rewrittenWithLens(appView, previousLens);
}
private void updateOptimizationInfos(
@@ -842,7 +864,7 @@
}
private OptionalInt getOrdinal(ObjectState state) {
- AbstractValue field = state.getAbstractFieldValue(ordinalField);
+ AbstractValue field = state.getAbstractFieldValue(getOrdinalField().getDefinition());
if (field.isSingleNumberValue()) {
return OptionalInt.of(field.asSingleNumberValue().getIntValue());
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
index a675735..4225447 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
@@ -11,6 +11,7 @@
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.GraphLens;
import com.android.tools.r8.ir.optimize.enums.eligibility.Reason;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
@@ -35,10 +36,16 @@
factory = appView.dexItemFactory();
}
- EnumUnboxingCandidateInfoCollection findCandidates() {
+ EnumUnboxingCandidateInfoCollection findCandidates(
+ GraphLens graphLensForPrimaryOptimizationPass) {
+ if (enumUnboxer.getOrdinalField() == null || enumUnboxer.getOrdinalField().isProgramField()) {
+ // This can happen when compiling for non standard libraries, in that case, this effectively
+ // disables the enum unboxer.
+ return enumToUnboxCandidates;
+ }
for (DexProgramClass clazz : appView.appInfo().classes()) {
if (isEnumUnboxingCandidate(clazz)) {
- enumToUnboxCandidates.addCandidate(clazz);
+ enumToUnboxCandidates.addCandidate(appView, clazz, graphLensForPrimaryOptimizationPass);
}
}
removeEnumsInAnnotations();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
index 7d85b8d..386bcb0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
@@ -4,13 +4,18 @@
package com.android.tools.r8.ir.optimize.enums;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
+import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -21,9 +26,14 @@
private final Map<DexType, EnumUnboxingCandidateInfo> enumTypeToInfo = new ConcurrentHashMap<>();
- public void addCandidate(DexProgramClass enumClass) {
+ public void addCandidate(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass enumClass,
+ GraphLens graphLensForPrimaryOptimizationPass) {
assert !enumTypeToInfo.containsKey(enumClass.type);
- enumTypeToInfo.put(enumClass.type, new EnumUnboxingCandidateInfo(enumClass));
+ enumTypeToInfo.put(
+ enumClass.type,
+ new EnumUnboxingCandidateInfo(appView, enumClass, graphLensForPrimaryOptimizationPass));
}
public void removeCandidate(DexProgramClass enumClass) {
@@ -62,10 +72,13 @@
return info.enumClass;
}
- public ProgramMethodSet allMethodDependencies() {
- ProgramMethodSet allMethodDependencies = ProgramMethodSet.create();
- for (EnumUnboxingCandidateInfo info : enumTypeToInfo.values()) {
- allMethodDependencies.addAll(info.methodDependencies);
+ public LongLivedProgramMethodSetBuilder<ProgramMethodSet> allMethodDependencies() {
+ Iterator<EnumUnboxingCandidateInfo> candidateInfoIterator = enumTypeToInfo.values().iterator();
+ assert candidateInfoIterator.hasNext();
+ LongLivedProgramMethodSetBuilder<ProgramMethodSet> allMethodDependencies =
+ candidateInfoIterator.next().methodDependencies;
+ while (candidateInfoIterator.hasNext()) {
+ allMethodDependencies.merge(candidateInfoIterator.next().methodDependencies);
}
return allMethodDependencies;
}
@@ -111,20 +124,27 @@
private static class EnumUnboxingCandidateInfo {
private final DexProgramClass enumClass;
- private final ProgramMethodSet methodDependencies = ProgramMethodSet.createConcurrent();
+ private final LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodDependencies;
private final Set<DexField> requiredInstanceFieldData = Sets.newConcurrentHashSet();
- public EnumUnboxingCandidateInfo(DexProgramClass enumClass) {
+ public EnumUnboxingCandidateInfo(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass enumClass,
+ GraphLens graphLensForPrimaryOptimizationPass) {
assert enumClass != null;
+ assert appView.graphLens() == graphLensForPrimaryOptimizationPass;
this.enumClass = enumClass;
+ this.methodDependencies =
+ LongLivedProgramMethodSetBuilder.createConcurrentForIdentitySet(
+ graphLensForPrimaryOptimizationPass);
}
public DexProgramClass getEnumClass() {
return enumClass;
}
- public void addMethodDependency(ProgramMethod programMethod) {
- methodDependencies.add(programMethod);
+ public void addMethodDependency(ProgramMethod method) {
+ methodDependencies.add(method);
}
public void addRequiredInstanceFieldData(DexField field) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index a5978fa..c9c7c40 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -46,8 +46,9 @@
// During the second IR processing enum unboxing is the only optimization rewriting
// prototype description, if this does not hold, remove the assertion and merge
// the two prototype changes.
- assert prototypeChanges.isEmpty();
- return prototypeChangesPerMethod.getOrDefault(method, RewrittenPrototypeDescription.none());
+ RewrittenPrototypeDescription enumUnboxingPrototypeChanges =
+ prototypeChangesPerMethod.getOrDefault(method, RewrittenPrototypeDescription.none());
+ return prototypeChanges.combine(enumUnboxingPrototypeChanges);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
index 9614ede..a239ebb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -31,10 +30,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.ValueType;
@@ -228,16 +224,13 @@
private DexEncodedField createValuesField(DexType sharedUtilityClassType) {
DexEncodedField valuesField =
- new DexEncodedField(
- dexItemFactory.createField(
- sharedUtilityClassType, dexItemFactory.intArrayType, "$VALUES"),
- FieldAccessFlags.createPublicStaticFinalSynthetic(),
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexEncodedField.NO_STATIC_VALUE,
- DexEncodedField.NOT_DEPRECATED,
- DexEncodedField.D8_R8_SYNTHESIZED,
- minApiLevelIfEnabledOrUnknown(appView));
+ DexEncodedField.syntheticBuilder()
+ .setField(
+ dexItemFactory.createField(
+ sharedUtilityClassType, dexItemFactory.intArrayType, "$VALUES"))
+ .setAccessFlags(FieldAccessFlags.createPublicStaticFinalSynthetic())
+ .setApiLevel(minApiLevelIfEnabledOrUnknown(appView))
+ .build();
fieldAccessInfoCollectionModifierBuilder
.recordFieldReadInUnknownContext(valuesField.getReference())
.recordFieldWriteInUnknownContext(valuesField.getReference());
@@ -248,17 +241,14 @@
private DexEncodedMethod createClassInitializer(
DexType sharedUtilityClassType, DexEncodedField valuesField) {
- return new DexEncodedMethod(
- dexItemFactory.createClassInitializer(sharedUtilityClassType),
- MethodAccessFlags.createForClassInitializer(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- createClassInitializerCode(sharedUtilityClassType, valuesField),
- DexEncodedMethod.D8_R8_SYNTHESIZED,
- CfVersion.V1_6,
- minApiLevelIfEnabledOrUnknown(appView),
- minApiLevelIfEnabledOrUnknown(appView));
+ return DexEncodedMethod.syntheticBuilder()
+ .setMethod(dexItemFactory.createClassInitializer(sharedUtilityClassType))
+ .setAccessFlags(MethodAccessFlags.createForClassInitializer())
+ .setCode(createClassInitializerCode(sharedUtilityClassType, valuesField))
+ .setClassFileVersion(CfVersion.V1_6)
+ .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView))
+ .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView))
+ .build();
}
private CfCode createClassInitializerCode(
@@ -292,20 +282,19 @@
private DexEncodedMethod createValuesMethod(
DexType sharedUtilityClassType, DexEncodedField valuesField) {
DexEncodedMethod valuesMethod =
- new DexEncodedMethod(
- dexItemFactory.createMethod(
- sharedUtilityClassType,
- dexItemFactory.createProto(dexItemFactory.intArrayType, dexItemFactory.intType),
- "values"),
- MethodAccessFlags.createPublicStaticSynthetic(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- createValuesMethodCode(sharedUtilityClassType, valuesField),
- DexEncodedMethod.D8_R8_SYNTHESIZED,
- CfVersion.V1_6,
- minApiLevelIfEnabledOrUnknown(appView),
- minApiLevelIfEnabledOrUnknown(appView));
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(
+ dexItemFactory.createMethod(
+ sharedUtilityClassType,
+ dexItemFactory.createProto(
+ dexItemFactory.intArrayType, dexItemFactory.intType),
+ "values"))
+ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+ .setCode(createValuesMethodCode(sharedUtilityClassType, valuesField))
+ .setClassFileVersion(CfVersion.V1_6)
+ .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView))
+ .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView))
+ .build();
this.valuesMethod = valuesMethod;
return valuesMethod;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java
index c411d08..2c012f0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java
@@ -8,12 +8,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
/**
* This class synthesizes library fields that we rely on for modeling.
@@ -35,13 +33,12 @@
DexEncodedField definition = enumClass.lookupField(field);
if (definition == null) {
enumClass.appendInstanceField(
- new DexEncodedField(
- field,
- FieldAccessFlags.fromCfAccessFlags(
- Constants.ACC_PRIVATE | Constants.ACC_FINAL),
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- null));
+ DexEncodedField.syntheticBuilder()
+ .setField(field)
+ .setAccessFlags(
+ FieldAccessFlags.fromCfAccessFlags(
+ Constants.ACC_PRIVATE | Constants.ACC_FINAL))
+ .build());
}
});
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
index 1f6c00a..0fbb615 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndField;
import com.android.tools.r8.graph.DexEncodedField;
@@ -58,6 +57,8 @@
private final DexItemFactory factory;
private final IRConverter converter;
+ private GraphLens graphLensForOptimizationPass;
+
// Represents a staticizing candidate with all information
// needed for staticizing.
final class CandidateInfo {
@@ -113,14 +114,36 @@
this.converter = converter;
}
+ public void prepareForPrimaryOptimizationPass(GraphLens graphLensForPrimaryOptimizationPass) {
+ collectCandidates();
+ this.graphLensForOptimizationPass = graphLensForPrimaryOptimizationPass;
+ }
+
+ public void prepareForSecondaryOptimizationPass(GraphLens graphLensForSecondaryOptimizationPass) {
+ // Rewrite all the referenced from sets such that they are all rewritten up until the lens of
+ // the second optimization pass. This is needed to ensure all elements in the referenced from
+ // sets are rewritten up until the same graph lens, in case any referenced from sets are
+ // extended during the secondary optimization pass.
+ assert appView.graphLens() == graphLensForSecondaryOptimizationPass;
+ referencedFrom
+ .values()
+ .forEach(
+ referencedFromBuilder ->
+ referencedFromBuilder.rewrittenWithLens(graphLensForSecondaryOptimizationPass));
+ this.graphLensForOptimizationPass = graphLensForSecondaryOptimizationPass;
+ }
+
// Before doing any usage-based analysis we collect a set of classes that can be
// candidates for staticizing. This analysis is very simple, but minimizes the
// set of eligible classes staticizer tracks and thus time and memory it needs.
- public final void collectCandidates(DexApplication app) {
+ public final void collectCandidates() {
Set<DexType> notEligible = Sets.newIdentityHashSet();
Map<DexType, DexEncodedField> singletonFields = new HashMap<>();
- app.classes()
+ assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
+ appView
+ .appInfo()
+ .classes()
.forEach(
cls -> {
// We only consider classes eligible for staticizing if there is just
@@ -169,20 +192,26 @@
});
// Finalize the set of the candidates.
- app.classes().forEach(cls -> {
- DexType type = cls.type;
- if (!notEligible.contains(type)) {
- DexEncodedField field = singletonFields.get(type);
- if (field != null && // Singleton field found
- !field.accessFlags.isVolatile() && // Don't remove volatile fields.
- !isPinned(cls, field)) { // Don't remove pinned objects.
- assert field.accessFlags.isStatic();
- // Note: we don't check that the field is final, since we will analyze
- // later how and where it is initialized.
- new CandidateInfo(cls, field); // will self-register
- }
- }
- });
+ appView
+ .appInfo()
+ .classes()
+ .forEach(
+ cls -> {
+ DexType type = cls.type;
+ if (!notEligible.contains(type)) {
+ DexEncodedField field = singletonFields.get(type);
+ if (field != null
+ && // Singleton field found
+ !field.accessFlags.isVolatile()
+ && // Don't remove volatile fields.
+ !isPinned(cls, field)) { // Don't remove pinned objects.
+ assert field.accessFlags.isStatic();
+ // Note: we don't check that the field is final, since we will analyze
+ // later how and where it is initialized.
+ new CandidateInfo(cls, field); // will self-register
+ }
+ }
+ });
}
private void markNotEligible(DexType type, Set<DexType> notEligible) {
@@ -374,9 +403,13 @@
}
private void addReferencedFrom(CandidateInfo info, ProgramMethod context) {
+ GraphLens currentGraphLens = appView.graphLens();
+ assert currentGraphLens == graphLensForOptimizationPass;
LongLivedProgramMethodSetBuilder<?> builder =
referencedFrom.computeIfAbsent(
- info, ignore -> LongLivedProgramMethodSetBuilder.createConcurrentForIdentitySet());
+ info,
+ ignore ->
+ LongLivedProgramMethodSetBuilder.createConcurrentForIdentitySet(currentGraphLens));
builder.add(context);
}
@@ -689,9 +722,8 @@
// 3. Rewrite methods referencing staticized members, also remove instance creation
//
public final void staticizeCandidates(
- OptimizationFeedback feedback, ExecutorService executorService, GraphLens applied)
- throws ExecutionException {
- new StaticizingProcessor(appView, this, converter, applied).run(feedback, executorService);
+ OptimizationFeedback feedback, ExecutorService executorService) throws ExecutionException {
+ new StaticizingProcessor(appView, this, converter).run(feedback, executorService);
}
private class CallSiteReferencesInvalidator extends UseRegistry {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 3e59aa8..2fbaa44 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.IRCode;
@@ -87,17 +86,14 @@
private final Map<DexField, CandidateInfo> singletonFields = new IdentityHashMap<>();
private final Map<DexMethod, CandidateInfo> singletonGetters = new IdentityHashMap<>();
private final Map<DexType, DexType> candidateToHostMapping = new IdentityHashMap<>();
- private final GraphLens applied;
StaticizingProcessor(
AppView<AppInfoWithLiveness> appView,
ClassStaticizer classStaticizer,
- IRConverter converter,
- GraphLens applied) {
+ IRConverter converter) {
this.appView = appView;
this.classStaticizer = classStaticizer;
this.converter = converter;
- this.applied = applied;
}
final void run(OptimizationFeedback feedback, ExecutorService executorService)
@@ -238,7 +234,7 @@
LongLivedProgramMethodSetBuilder<?> referencedFromBuilder =
classStaticizer.referencedFrom.remove(info);
assert referencedFromBuilder != null;
- referencedFrom = referencedFromBuilder.build(appView, applied);
+ referencedFrom = referencedFromBuilder.build(appView);
materializedReferencedFromCollections.put(info, referencedFrom);
} else {
referencedFrom = ProgramMethodSet.empty();
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 2761296..f81b135 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
@@ -7,7 +7,6 @@
import static com.android.tools.r8.optimize.argumentpropagation.utils.StronglyConnectedProgramClasses.computeStronglyConnectedProgramClasses;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.graph.ProgramMethod;
@@ -15,7 +14,6 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
-import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.VirtualRootMethodsAnalysis;
@@ -128,15 +126,30 @@
throws ExecutionException {
assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
timing.begin("Argument propagator");
+
+ // Compute the strongly connected program components for parallel execution.
ImmediateProgramSubtypingInfo immediateSubtypingInfo =
ImmediateProgramSubtypingInfo.create(appView);
List<Set<DexProgramClass>> stronglyConnectedProgramComponents =
computeStronglyConnectedProgramClasses(appView, immediateSubtypingInfo);
+
+ // Set the optimization info on each method.
populateParameterOptimizationInfo(
immediateSubtypingInfo, stronglyConnectedProgramComponents, executorService, timing);
- optimizeMethodParameters(
- immediateSubtypingInfo, stronglyConnectedProgramComponents, executorService);
- enqueueMethodsForProcessing(postMethodProcessorBuilder);
+
+ // 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.
+ ArgumentPropagatorGraphLens graphLens =
+ optimizeMethodParameters(stronglyConnectedProgramComponents, executorService);
+
+ // Find all the code objects that need reprocessing.
+ new ArgumentPropagatorMethodReprocessingEnqueuer(appView)
+ .enqueueMethodForReprocessing(graphLens, postMethodProcessorBuilder, executorService);
+
+ // Finally, apply the graph lens to the program (i.e., remove constant parameters from method
+ // definitions).
+ new ArgumentPropagatorApplicationFixer(appView, graphLens).fixupApplication(executorService);
+
timing.end();
}
@@ -169,47 +182,20 @@
}
/** Called by {@link IRConverter} to optimize method definitions. */
- private void optimizeMethodParameters(
- ImmediateProgramSubtypingInfo immediateSubtypingInfo,
+ private ArgumentPropagatorGraphLens optimizeMethodParameters(
List<Set<DexProgramClass>> stronglyConnectedProgramComponents,
ExecutorService executorService)
throws ExecutionException {
Collection<ArgumentPropagatorGraphLens.Builder> partialGraphLensBuilders =
ThreadUtils.processItemsWithResults(
stronglyConnectedProgramComponents,
- classes ->
- new ArgumentPropagatorProgramOptimizer(appView, immediateSubtypingInfo)
- .optimize(classes),
+ classes -> new ArgumentPropagatorProgramOptimizer(appView).optimize(classes),
executorService);
// Merge all the partial, disjoint graph lens builders into a single graph lens.
ArgumentPropagatorGraphLens.Builder graphLensBuilder =
ArgumentPropagatorGraphLens.builder(appView);
partialGraphLensBuilders.forEach(graphLensBuilder::mergeDisjoint);
-
- ArgumentPropagatorGraphLens graphLens = graphLensBuilder.build();
- if (graphLens != null) {
- appView.setGraphLens(graphLens);
- }
- }
-
- /**
- * Called by {@link IRConverter} to add all methods that require reprocessing to {@param
- * postMethodProcessorBuilder}.
- */
- private void enqueueMethodsForProcessing(PostMethodProcessor.Builder postMethodProcessorBuilder) {
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- clazz.forEachProgramMethodMatching(
- DexEncodedMethod::hasCode,
- method -> {
- CallSiteOptimizationInfo callSiteOptimizationInfo =
- method.getDefinition().getCallSiteOptimizationInfo();
- if (callSiteOptimizationInfo.isConcreteCallSiteOptimizationInfo()
- && !appView.appInfo().isNeverReprocessMethod(method.getReference())) {
- postMethodProcessorBuilder.add(method);
- appView.testing().callSiteOptimizationInfoInspector.accept(method);
- }
- });
- }
+ return graphLensBuilder.build();
}
}
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
new file mode 100644
index 0000000..346e3fc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -0,0 +1,61 @@
+// 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 com.android.tools.r8.graph.AppView;
+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.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ThreadUtils;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Takes as input a mapping from old method signatures to new method signatures (with parameters
+ * removed), and rewrites all method definitions in the application to their new method signatures.
+ */
+public class ArgumentPropagatorApplicationFixer {
+
+ private final AppView<AppInfoWithLiveness> appView;
+ private final ArgumentPropagatorGraphLens graphLens;
+
+ public ArgumentPropagatorApplicationFixer(
+ AppView<AppInfoWithLiveness> appView, ArgumentPropagatorGraphLens graphLens) {
+ this.appView = appView;
+ this.graphLens = graphLens;
+ }
+
+ public void fixupApplication(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) {
+ return;
+ }
+
+ // TODO(b/190154391): Do not naively visit all classes, when only few require changes.
+ ThreadUtils.processItems(appView.appInfo().classes(), this::fixupClass, executorService);
+ appView.setGraphLens(graphLens);
+ }
+
+ private void fixupClass(DexProgramClass clazz) {
+ MethodCollection methodCollection = clazz.getMethodCollection();
+ methodCollection.replaceMethods(
+ method -> {
+ DexMethod methodReferenceBeforeParameterRemoval = method.getReference();
+ DexMethod methodReferenceAfterParameterRemoval =
+ graphLens.internalGetNextMethodSignature(methodReferenceBeforeParameterRemoval);
+ if (methodReferenceAfterParameterRemoval == methodReferenceBeforeParameterRemoval) {
+ return method;
+ }
+
+ return method.toTypeSubstitutedMethod(
+ methodReferenceAfterParameterRemoval,
+ builder -> {
+ // TODO(b/190154391): fixup parameter annotations, if any.
+ });
+ });
+ }
+}
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 0110197..c60640c 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
@@ -5,18 +5,27 @@
package com.android.tools.r8.optimize.argumentpropagation;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+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.shaking.AppInfoWithLiveness;
+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 java.util.IdentityHashMap;
+import java.util.Map;
-public class ArgumentPropagatorGraphLens extends NonIdentityGraphLens {
+public class ArgumentPropagatorGraphLens extends NestedGraphLens {
- ArgumentPropagatorGraphLens(AppView<AppInfoWithLiveness> appView) {
- super(appView);
+ private final Map<DexMethod, ArgumentInfoCollection> removedParameters;
+
+ ArgumentPropagatorGraphLens(
+ AppView<AppInfoWithLiveness> appView,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap,
+ Map<DexMethod, ArgumentInfoCollection> removedParameters) {
+ super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP);
+ this.removedParameters = removedParameters;
}
public static Builder builder(AppView<AppInfoWithLiveness> appView) {
@@ -24,85 +33,67 @@
}
@Override
- public DexType getOriginalType(DexType type) {
- return getPrevious().getOriginalType(type);
+ protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
+ RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
+ DexMethod previous = internalGetPreviousMethodSignature(method);
+ if (previous == method) {
+ assert !removedParameters.containsKey(method);
+ return prototypeChanges;
+ }
+ return prototypeChanges.withRemovedArguments(
+ removedParameters.getOrDefault(method, ArgumentInfoCollection.empty()));
}
@Override
- public Iterable<DexType> getOriginalTypes(DexType type) {
- return getPrevious().getOriginalTypes(type);
+ public DexMethod internalGetPreviousMethodSignature(DexMethod method) {
+ return super.internalGetPreviousMethodSignature(method);
}
@Override
- public DexField getOriginalFieldSignature(DexField field) {
- return getPrevious().getOriginalFieldSignature(field);
- }
-
- @Override
- public DexField getRenamedFieldSignature(DexField originalField) {
- return getPrevious().getRenamedFieldSignature(originalField);
- }
-
- @Override
- public DexMethod getOriginalMethodSignature(DexMethod method) {
- return getPrevious().getOriginalMethodSignature(method);
- }
-
- @Override
- public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
- return applied != this
- ? getPrevious().getRenamedMethodSignature(originalMethod, applied)
- : originalMethod;
- }
-
- @Override
- protected DexType internalDescribeLookupClassType(DexType previous) {
- return previous;
- }
-
- @Override
- protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
- return previous;
- }
-
- @Override
- protected MethodLookupResult internalDescribeLookupMethod(
- MethodLookupResult previous, DexMethod context) {
- return previous;
- }
-
- @Override
- protected DexMethod internalGetPreviousMethodSignature(DexMethod method) {
- return method;
- }
-
- @Override
- public boolean isContextFreeForMethods() {
- return getPrevious().isContextFreeForMethods();
- }
-
- @Override
- public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(DexMethod method) {
- return getPrevious().lookupPrototypeChangesForMethodDefinition(method);
+ public DexMethod internalGetNextMethodSignature(DexMethod method) {
+ return super.internalGetNextMethodSignature(method);
}
public static class Builder {
private final AppView<AppInfoWithLiveness> appView;
+ private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures =
+ new BidirectionalOneToOneHashMap<>();
+ private final Map<DexMethod, ArgumentInfoCollection> removedParameters =
+ new IdentityHashMap<>();
Builder(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
+ public boolean isEmpty() {
+ return newMethodSignatures.isEmpty();
+ }
+
public ArgumentPropagatorGraphLens.Builder mergeDisjoint(
ArgumentPropagatorGraphLens.Builder partialGraphLensBuilder) {
- // TODO(b/190154391): Implement.
+ newMethodSignatures.putAll(partialGraphLensBuilder.newMethodSignatures);
+ removedParameters.putAll(partialGraphLensBuilder.removedParameters);
+ return this;
+ }
+
+ 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();
+ }
return this;
}
public ArgumentPropagatorGraphLens build() {
- // TODO(b/190154391): Implement.
- return null;
+ return isEmpty()
+ ? null
+ : new ArgumentPropagatorGraphLens(appView, newMethodSignatures, removedParameters);
}
}
}
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
new file mode 100644
index 0000000..3c732df
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -0,0 +1,189 @@
+// 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 com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+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.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor;
+import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+/** Finds the methods in the program that should be reprocessed due to argument propagation. */
+public class ArgumentPropagatorMethodReprocessingEnqueuer {
+
+ private final AppView<AppInfoWithLiveness> appView;
+
+ public ArgumentPropagatorMethodReprocessingEnqueuer(AppView<AppInfoWithLiveness> appView) {
+ this.appView = appView;
+ }
+
+ /**
+ * Called indirectly from {@link IRConverter} to add all methods that require reprocessing to
+ * {@param postMethodProcessorBuilder}.
+ */
+ public void enqueueMethodForReprocessing(
+ ArgumentPropagatorGraphLens graphLens,
+ PostMethodProcessor.Builder postMethodProcessorBuilder,
+ ExecutorService executorService)
+ throws ExecutionException {
+ // Bring the methods to reprocess set up-to-date with the current graph lens (i.e., the one
+ // prior to the argument propagator lens, which has not yet been installed!).
+ LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder =
+ postMethodProcessorBuilder
+ .getMethodsToReprocessBuilder()
+ .rewrittenWithLens(appView.graphLens());
+ enqueueMethodsWithNonTrivialOptimizationInfo(methodsToReprocessBuilder);
+ if (graphLens != null) {
+ enqueueAffectedCallers(graphLens, methodsToReprocessBuilder, executorService);
+ }
+ }
+
+ private void enqueueMethodsWithNonTrivialOptimizationInfo(
+ LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder) {
+ GraphLens currentGraphLens = appView.graphLens();
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ clazz.forEachProgramMethodMatching(
+ DexEncodedMethod::hasCode,
+ method -> {
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
+ if (callSiteOptimizationInfo.isConcreteCallSiteOptimizationInfo()
+ && !appView.appInfo().isNeverReprocessMethod(method.getReference())) {
+ methodsToReprocessBuilder.add(method, currentGraphLens);
+ appView.testing().callSiteOptimizationInfoInspector.accept(method);
+ }
+ });
+ }
+ }
+
+ // TODO(b/190154391): This could invalidate the @NeverReprocessMethod testing annotations (non
+ // critical). If @NeverReprocessMethod is used, we would need to scan the application to mark
+ // methods as unoptimizable prior to removing parameters from the application.
+ private void enqueueAffectedCallers(
+ ArgumentPropagatorGraphLens graphLens,
+ LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder,
+ ExecutorService executorService)
+ throws ExecutionException {
+ Collection<List<ProgramMethod>> methodsToReprocess =
+ ThreadUtils.processItemsWithResults(
+ appView.appInfo().classes(),
+ clazz -> {
+ List<ProgramMethod> methodsToReprocessInClass = new ArrayList<>();
+ clazz.forEachProgramMethodMatching(
+ DexEncodedMethod::hasCode,
+ method -> {
+ AffectedMethodUseRegistry registry =
+ new AffectedMethodUseRegistry(appView, graphLens);
+ method.registerCodeReferences(registry);
+ if (registry.isAffected()) {
+ methodsToReprocessInClass.add(method);
+ }
+ });
+ return methodsToReprocessInClass;
+ },
+ executorService);
+ GraphLens currentGraphLens = appView.graphLens();
+ methodsToReprocess.forEach(
+ methodsToReprocessForClass ->
+ methodsToReprocessBuilder.addAll(methodsToReprocessForClass, currentGraphLens));
+ }
+
+ static class AffectedMethodUseRegistry extends UseRegistry {
+
+ 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());
+ this.appView = appView;
+ this.graphLens = graphLens;
+ }
+
+ boolean isAffected() {
+ return affected;
+ }
+
+ @Override
+ public void registerInvokeDirect(DexMethod method) {
+ registerInvokeMethod(method);
+ }
+
+ @Override
+ public void registerInvokeInterface(DexMethod method) {
+ registerInvokeMethod(method);
+ }
+
+ @Override
+ public void registerInvokeStatic(DexMethod method) {
+ registerInvokeMethod(method);
+ }
+
+ @Override
+ public void registerInvokeSuper(DexMethod method) {
+ registerInvokeMethod(method);
+ }
+
+ @Override
+ public void registerInvokeVirtual(DexMethod method) {
+ registerInvokeMethod(method);
+ }
+
+ private void registerInvokeMethod(DexMethod method) {
+ SingleResolutionResult resolutionResult =
+ appView.appInfo().unsafeResolveMethodDueToDexFormat(method).asSingleResolution();
+ if (resolutionResult == null || !resolutionResult.getResolvedHolder().isProgramClass()) {
+ return;
+ }
+
+ ProgramMethod resolvedMethod = resolutionResult.getResolvedProgramMethod();
+ DexMethod rewrittenMethodReference =
+ graphLens.internalGetNextMethodSignature(resolvedMethod.getReference());
+ if (rewrittenMethodReference != resolvedMethod.getReference()) {
+ affected = true;
+ // TODO(b/150583533): break/abort!
+ }
+ }
+
+ @Override
+ public void registerInitClass(DexType type) {}
+
+ @Override
+ public void registerInstanceFieldRead(DexField field) {}
+
+ @Override
+ public void registerInstanceFieldWrite(DexField field) {}
+
+ @Override
+ public void registerStaticFieldRead(DexField field) {}
+
+ @Override
+ public void registerStaticFieldWrite(DexField field) {}
+
+ @Override
+ public void registerTypeReference(DexType type) {}
+ }
+}
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 859830b..b10ff8d 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
@@ -4,24 +4,61 @@
package com.android.tools.r8.optimize.argumentpropagation;
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexMethodSignature;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
+import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+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.InternalOptions;
+import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.Iterables;
+import it.unimi.dsi.fastutil.ints.IntArraySet;
+import it.unimi.dsi.fastutil.ints.IntSet;
+import it.unimi.dsi.fastutil.ints.IntSets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
+import java.util.function.IntPredicate;
public class ArgumentPropagatorProgramOptimizer {
private final AppView<AppInfoWithLiveness> appView;
- private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
- public ArgumentPropagatorProgramOptimizer(
- AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
+ private final DexItemFactory dexItemFactory;
+
+ private final InternalOptions options;
+
+ private final Map<DexMethodSignature, IntSet> removableVirtualMethodParameters = new HashMap<>();
+
+ // Reserved names, i.e., mappings from pairs (old method signature, number of removed arguments)
+ // to the new method signature for that method.
+ private final Map<DexMethodSignature, Map<IntSet, DexMethodSignature>> newMethodSignatures =
+ new HashMap<>();
+
+ // Occupied method signatures (inverse of reserved names). Used to effectively check if a given
+ // method signature is already reserved.
+ private final Map<DexMethodSignature, Pair<IntSet, DexMethodSignature>> occupiedMethodSignatures =
+ new HashMap<>();
+
+ public ArgumentPropagatorProgramOptimizer(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
- this.immediateSubtypingInfo = immediateSubtypingInfo;
+ this.dexItemFactory = appView.dexItemFactory();
+ this.options = appView.options();
}
- // TODO(b/190154391): Remove parameters with constant values.
// TODO(b/190154391): Remove unused parameters by simulating they are constant.
// TODO(b/190154391): Strengthen the static type of parameters.
// TODO(b/190154391): If we learn that a method returns a constant, then consider changing its
@@ -32,6 +69,279 @@
// information to all call sites.
public ArgumentPropagatorGraphLens.Builder optimize(
Set<DexProgramClass> stronglyConnectedProgramClasses) {
- return ArgumentPropagatorGraphLens.builder(appView);
+ // First reserve pinned method signatures.
+ reservePinnedMethodSignatures(stronglyConnectedProgramClasses);
+
+ // To ensure that we preserve the overriding relationships between methods, we only remove a
+ // constant or unused parameter from a virtual method when it can be removed from all other
+ // virtual methods in the component with the same method signature.
+ computeRemovableVirtualMethodParameters(stronglyConnectedProgramClasses);
+
+ // Build a graph lens while visiting the classes in the component.
+ // TODO(b/190154391): Consider visiting the interfaces first, and then processing the
+ // (non-interface) classes in top-down order to reduce the amount of reserved names.
+ ArgumentPropagatorGraphLens.Builder partialGraphLensBuilder =
+ ArgumentPropagatorGraphLens.builder(appView);
+ for (DexProgramClass clazz : stronglyConnectedProgramClasses) {
+ visitClass(clazz, partialGraphLensBuilder);
+ }
+ return partialGraphLensBuilder;
+ }
+
+ private void reservePinnedMethodSignatures(Set<DexProgramClass> stronglyConnectedProgramClasses) {
+ DexMethodSignatureSet pinnedMethodSignatures = DexMethodSignatureSet.create();
+ for (DexProgramClass clazz : stronglyConnectedProgramClasses) {
+ clazz.forEachProgramMethod(
+ method -> {
+ if (!appView.getKeepInfo(method).isShrinkingAllowed(options)) {
+ pinnedMethodSignatures.add(method.getMethodSignature());
+ }
+ });
+ }
+ pinnedMethodSignatures.forEach(
+ signature -> reserveMethodSignature(signature, signature, IntSets.EMPTY_SET));
+ }
+
+ private void reserveMethodSignature(
+ DexMethodSignature newMethodSignature,
+ DexMethodSignature originalMethodSignature,
+ IntSet removedParameterIndices) {
+ // Record that methods with the given signature and removed parameters should be mapped to the
+ // new signature.
+ newMethodSignatures
+ .computeIfAbsent(originalMethodSignature, ignoreKey(HashMap::new))
+ .put(removedParameterIndices, newMethodSignature);
+
+ // Record that the new method signature is used, by a method with the old signature that had the
+ // given removed parameters.
+ occupiedMethodSignatures.put(
+ newMethodSignature, new Pair<>(removedParameterIndices, originalMethodSignature));
+ }
+
+ private void computeRemovableVirtualMethodParameters(
+ Set<DexProgramClass> stronglyConnectedProgramClasses) {
+ // Group the virtual methods in the component by their signatures.
+ Map<DexMethodSignature, ProgramMethodSet> virtualMethodsBySignature =
+ computeVirtualMethodsBySignature(stronglyConnectedProgramClasses);
+ virtualMethodsBySignature.forEach(
+ (signature, methods) -> {
+ // Check that there are no keep rules that prohibit parameter removal from any of the
+ // methods.
+ if (Iterables.any(methods, method -> !isParameterRemovalAllowed(method))) {
+ return;
+ }
+
+ // Find the parameters that are constant or unused in all methods.
+ IntSet removableVirtualMethodParametersInAllMethods = new IntArraySet();
+ for (int parameterIndex = 1;
+ parameterIndex < signature.getProto().getArity() + 1;
+ parameterIndex++) {
+ if (canRemoveParameterFromVirtualMethods(parameterIndex, methods)) {
+ removableVirtualMethodParametersInAllMethods.add(parameterIndex);
+ }
+ }
+
+ // If any parameters could be removed, record it.
+ if (!removableVirtualMethodParametersInAllMethods.isEmpty()) {
+ removableVirtualMethodParameters.put(
+ signature, removableVirtualMethodParametersInAllMethods);
+ }
+ });
+ }
+
+ private Map<DexMethodSignature, ProgramMethodSet> computeVirtualMethodsBySignature(
+ Set<DexProgramClass> stronglyConnectedProgramClasses) {
+ Map<DexMethodSignature, ProgramMethodSet> virtualMethodsBySignature = new HashMap<>();
+ for (DexProgramClass clazz : stronglyConnectedProgramClasses) {
+ clazz.forEachProgramVirtualMethod(
+ method ->
+ virtualMethodsBySignature
+ .computeIfAbsent(method.getMethodSignature(), ignoreKey(ProgramMethodSet::create))
+ .add(method));
+ }
+ return virtualMethodsBySignature;
+ }
+
+ private boolean isParameterRemovalAllowed(ProgramMethod method) {
+ return appView.getKeepInfo(method).isParameterRemovalAllowed(options)
+ && !method.getDefinition().isLibraryMethodOverride().isPossiblyTrue();
+ }
+
+ private boolean canRemoveParameterFromVirtualMethods(
+ int parameterIndex, ProgramMethodSet methods) {
+ for (ProgramMethod method : methods) {
+ if (method.getDefinition().isAbstract()) {
+ DexProgramClass holder = method.getHolder();
+ if (holder.isInterface()) {
+ ObjectAllocationInfoCollection objectAllocationInfoCollection =
+ appView.appInfo().getObjectAllocationInfoCollection();
+ if (objectAllocationInfoCollection.isImmediateInterfaceOfInstantiatedLambda(holder)) {
+ return false;
+ }
+ }
+ // OK, this parameter can be removed.
+ continue;
+ }
+ CallSiteOptimizationInfo optimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
+ if (optimizationInfo.isConcreteCallSiteOptimizationInfo()) {
+ ConcreteCallSiteOptimizationInfo concreteOptimizationInfo =
+ optimizationInfo.asConcreteCallSiteOptimizationInfo();
+ AbstractValue abstractValue =
+ concreteOptimizationInfo.getAbstractArgumentValue(parameterIndex);
+ if (abstractValue.isSingleValue()
+ && abstractValue.asSingleValue().isMaterializableInContext(appView, method)) {
+ // OK, this parameter has a constant value and can be removed.
+ continue;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ private void visitClass(
+ DexProgramClass clazz, ArgumentPropagatorGraphLens.Builder partialGraphLensBuilder) {
+ clazz.forEachProgramMethod(
+ method -> {
+ ArgumentInfoCollection removableParameters =
+ method.getDefinition().belongsToDirectPool()
+ ? computeRemovableParametersFromDirectMethod(method)
+ : computeRemovableParametersFromVirtualMethod(method);
+ DexMethod newMethodSignature = getNewMethodSignature(method, removableParameters);
+ partialGraphLensBuilder.recordMove(
+ method.getReference(), newMethodSignature, removableParameters);
+ });
+ }
+
+ private DexMethod getNewMethodSignature(
+ ProgramMethod method, ArgumentInfoCollection removableParameters) {
+ DexMethodSignature methodSignatureWithoutParametersRemoved = method.getMethodSignature();
+ IntSet removableParameterIndices = removableParameters.getKeys();
+
+ // Check if there is a reserved signature for this already.
+ DexMethodSignature reservedSignature =
+ newMethodSignatures
+ .getOrDefault(methodSignatureWithoutParametersRemoved, Collections.emptyMap())
+ .get(removableParameterIndices);
+ if (reservedSignature != null) {
+ return reservedSignature.withHolder(method.getHolderType(), dexItemFactory);
+ }
+
+ DexMethod methodReferenceWithParametersRemoved =
+ removableParameters.rewriteMethod(method, dexItemFactory);
+ DexMethodSignature methodSignatureWithParametersRemoved =
+ methodReferenceWithParametersRemoved.getSignature();
+
+ // Find a method signature. First check if the current signature is available.
+ if (!occupiedMethodSignatures.containsKey(methodSignatureWithParametersRemoved)) {
+ reserveMethodSignature(
+ methodSignatureWithParametersRemoved,
+ methodSignatureWithoutParametersRemoved,
+ removableParameterIndices);
+ return methodReferenceWithParametersRemoved;
+ }
+
+ Pair<IntSet, DexMethodSignature> occupant =
+ occupiedMethodSignatures.get(methodSignatureWithParametersRemoved);
+ // In this case we should have found a reserved method signature above.
+ assert !(occupant.getFirst().equals(removableParameterIndices)
+ && occupant.getSecond().equals(methodSignatureWithoutParametersRemoved));
+
+ // We need to find a new name for this method, since the signature is already occupied.
+ // TODO(b/190154391): Instead of generating a new name, we could also try permuting the order of
+ // parameters.
+ DexMethod newMethod =
+ dexItemFactory.createFreshMethodNameWithoutHolder(
+ method.getName().toString(),
+ methodReferenceWithParametersRemoved.getProto(),
+ method.getHolderType(),
+ candidate -> {
+ Pair<IntSet, DexMethodSignature> candidateOccupant =
+ occupiedMethodSignatures.get(candidate.getSignature());
+ if (candidateOccupant == null) {
+ return true;
+ }
+ return candidateOccupant.getFirst().equals(removableParameterIndices)
+ && candidateOccupant.getSecond().equals(methodSignatureWithoutParametersRemoved);
+ });
+
+ // Reserve the newly generated method signature.
+ reserveMethodSignature(
+ newMethod.getSignature(),
+ methodSignatureWithoutParametersRemoved,
+ removableParameterIndices);
+
+ return newMethod;
+ }
+
+ private ArgumentInfoCollection computeRemovableParametersFromDirectMethod(ProgramMethod method) {
+ assert method.getDefinition().belongsToDirectPool();
+ if (method.getDefinition().isInstanceInitializer()) {
+ // TODO(b/190154391): Allow parameter removal from initializers. We need to guarantee absence
+ // of collisions since initializers can't be renamed.
+ return ArgumentInfoCollection.empty();
+ }
+ return computeRemovableParametersFromMethod(method);
+ }
+
+ private ArgumentInfoCollection computeRemovableParametersFromVirtualMethod(ProgramMethod method) {
+ IntSet removableParameterIndices =
+ removableVirtualMethodParameters.getOrDefault(
+ method.getMethodSignature(), IntSets.EMPTY_SET);
+ if (removableParameterIndices.isEmpty()) {
+ return ArgumentInfoCollection.empty();
+ }
+
+ if (method.getAccessFlags().isAbstract()) {
+ // Treat the parameters as unused.
+ ArgumentInfoCollection.Builder removableParametersBuilder = ArgumentInfoCollection.builder();
+ for (int removableParameterIndex : removableParameterIndices) {
+ removableParametersBuilder.addArgumentInfo(
+ removableParameterIndex,
+ RemovedArgumentInfo.builder()
+ .setType(method.getArgumentType(removableParameterIndex))
+ .build());
+ }
+ return removableParametersBuilder.build();
+ }
+
+ ArgumentInfoCollection removableParameters =
+ computeRemovableParametersFromMethod(method, removableParameterIndices::contains);
+ assert removableParameters.size() == removableParameterIndices.size();
+ return removableParameters;
+ }
+
+ private ArgumentInfoCollection computeRemovableParametersFromMethod(ProgramMethod method) {
+ return computeRemovableParametersFromMethod(method, parameterIndex -> true);
+ }
+
+ private ArgumentInfoCollection computeRemovableParametersFromMethod(
+ ProgramMethod method, IntPredicate removableParameterIndices) {
+ ConcreteCallSiteOptimizationInfo optimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo().asConcreteCallSiteOptimizationInfo();
+ if (optimizationInfo == null) {
+ return ArgumentInfoCollection.empty();
+ }
+
+ ArgumentInfoCollection.Builder removableParametersBuilder = ArgumentInfoCollection.builder();
+ for (int argumentIndex = method.getDefinition().getFirstNonReceiverArgumentIndex();
+ argumentIndex < method.getDefinition().getNumberOfArguments();
+ argumentIndex++) {
+ if (!removableParameterIndices.test(argumentIndex)) {
+ continue;
+ }
+ AbstractValue abstractValue = optimizationInfo.getAbstractArgumentValue(argumentIndex);
+ if (abstractValue.isSingleValue()
+ && abstractValue.asSingleValue().isMaterializableInContext(appView, method)) {
+ removableParametersBuilder.addArgumentInfo(
+ argumentIndex,
+ RemovedArgumentInfo.builder()
+ .setSingleValue(abstractValue.asSingleValue())
+ .setType(method.getArgumentType(argumentIndex))
+ .build());
+ }
+ }
+ return removableParametersBuilder.build();
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java
index 3244db4..02db24d 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java
@@ -51,12 +51,12 @@
return this;
}
- public AbstractValue getAbstractValue() {
- return abstractValue;
- }
-
@Override
public AbstractValue getAbstractValue(AppView<AppInfoWithLiveness> appView) {
+ if (getDynamicType().getNullability().isDefinitelyNull()) {
+ assert abstractValue == null || abstractValue.isNull();
+ return appView.abstractValueFactory().createNullValue();
+ }
return abstractValue;
}
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 acc8410..55278ec 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -933,7 +933,8 @@
if (!options().enableValuePropagation || neverPropagateValue.contains(method)) {
return false;
}
- if (isPinned(method) && !method.getReturnType().isAlwaysNull(this)) {
+ if (!method.getReturnType().isAlwaysNull(this)
+ && !getKeepInfo().getMethodInfo(method, this).isInliningAllowed(options())) {
return false;
}
return true;
@@ -1315,7 +1316,11 @@
if (refinedReceiverClass.isProgramClass()) {
DexClassAndMethod clazzAndMethod =
resolution.lookupVirtualDispatchTarget(refinedReceiverClass.asProgramClass(), this);
- if (clazzAndMethod == null || isPinned(clazzAndMethod.getDefinition().getReference())) {
+ if (clazzAndMethod == null
+ || (clazzAndMethod.isProgramMethod()
+ && !getKeepInfo()
+ .getMethodInfo(clazzAndMethod.asProgramMethod())
+ .isOptimizationAllowed(options()))) {
// TODO(b/150640456): We should maybe only consider program methods.
return DexEncodedMethod.SENTINEL;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
index bfc3ae7..129acae 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -10,13 +10,11 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Visibility;
@@ -82,17 +80,15 @@
| Constants.ACC_FINAL
| Constants.ACC_PUBLIC
| Constants.ACC_STATIC);
- boolean deprecated = false;
encodedClinitField =
- new DexEncodedField(
- appView.dexItemFactory().createField(clazz.type, clinitField.type, clinitField.name),
- accessFlags,
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- null,
- deprecated,
- DexEncodedField.D8_R8_SYNTHESIZED,
- minApiLevelIfEnabledOrUnknown(appView));
+ DexEncodedField.syntheticBuilder()
+ .setField(
+ appView
+ .dexItemFactory()
+ .createField(clazz.type, clinitField.type, clinitField.name))
+ .setAccessFlags(accessFlags)
+ .setApiLevel(minApiLevelIfEnabledOrUnknown(appView))
+ .build();
clazz.appendStaticField(encodedClinitField);
}
lensBuilder.map(type, encodedClinitField.getReference());
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 66e9136..895e610 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -108,6 +109,7 @@
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringTypeLookupResult;
+import com.android.tools.r8.position.Position;
import com.android.tools.r8.shaking.AnnotationMatchResult.MatchedAnnotation;
import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
import com.android.tools.r8.shaking.EnqueuerEvent.ClassEnqueuerEvent;
@@ -3933,7 +3935,19 @@
assert workList.isEmpty();
R8PostProcessingDesugaringEventConsumer eventConsumer =
- CfPostProcessingDesugaringEventConsumer.createForR8(syntheticAdditions, desugaring);
+ CfPostProcessingDesugaringEventConsumer.createForR8(
+ syntheticAdditions,
+ desugaring,
+ (context, missing) ->
+ missingClassesBuilder.addNewMissingClassWithDesugarDiagnostic(
+ missing,
+ context,
+ new InterfaceDesugarMissingTypeDiagnostic(
+ context.getOrigin(),
+ Position.UNKNOWN,
+ missing.asClassReference(),
+ context.getType().asClassReference(),
+ null)));
InterfaceMethodProcessorFacade interfaceDesugaring =
desugaring.getInterfaceMethodPostProcessingDesugaringR8(
ExcludeDexResources, liveMethods::contains, interfaceProcessor);
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
index c3165ad..f846462 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
@@ -70,6 +70,10 @@
return allowAnnotationRemoval;
}
+ public boolean isParameterRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
+ return isOptimizationAllowed(configuration) && isShrinkingAllowed(configuration);
+ }
+
/**
* True if an item must be present in the output.
*
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 dd4226c..79fac0a 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -54,6 +54,10 @@
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/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index 1dd5360..ac8f1fb 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.diagnostic.internal.DefinitionContextUtils;
import com.android.tools.r8.diagnostic.internal.MissingClassInfoImpl;
import com.android.tools.r8.diagnostic.internal.MissingDefinitionsDiagnosticImpl;
+import com.android.tools.r8.errors.DesugarDiagnostic;
import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
@@ -89,6 +90,17 @@
}
}
+ public void addNewMissingClassWithDesugarDiagnostic(
+ DexType type, ProgramDerivedContext context, DesugarDiagnostic diagnostic) {
+ // TODO(b/175659048): At this point we just throw out the diagnostic and report the
+ // missing classes only. We should instead report the most specific diagnostic as the
+ // information about missing for desugar is strictly more valuable than just missing.
+ // Note that we should have deterministic reporting and so we should collect all of the
+ // contexts for which desugaring needed the type and report all of those in the same
+ // way as we do for missing classes.
+ addNewMissingClass(type, context);
+ }
+
public void legacyAddNewMissingClass(DexType type) {
if (!alreadyMissingClasses.contains(type)) {
// The legacy reporting is context insensitive, so we just use an empty set of contexts.
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 27d25bb..6a89e9b 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -9,12 +9,12 @@
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
+import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
@@ -46,7 +46,6 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.SubtypingInfo;
@@ -1440,18 +1439,17 @@
// be updated by the end of vertical class merging.
synthesizedBridges.add(code);
+ CfVersion classFileVersion =
+ method.hasClassFileVersion() ? method.getClassFileVersion() : null;
DexEncodedMethod bridge =
- new DexEncodedMethod(
- newMethod,
- accessFlags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- true,
- method.hasClassFileVersion() ? method.getClassFileVersion() : null,
- method.getApiLevelForDefinition(),
- method.getApiLevelForDefinition());
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(newMethod)
+ .setAccessFlags(accessFlags)
+ .setCode(code)
+ .setClassFileVersion(classFileVersion)
+ .setApiLevelForDefinition(method.getApiLevelForDefinition())
+ .setApiLevelForCode(method.getApiLevelForDefinition())
+ .build();
bridge.setLibraryMethodOverride(method.isLibraryMethodOverride());
if (method.accessFlags.isPromotedToPublic()) {
// The bridge is now the public method serving the role of the original method, and should
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
index 196af3b..0e45bd8 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -104,21 +104,21 @@
DexEncodedMethod build() {
assert name != null;
- boolean isCompilerSynthesized = true;
DexMethod methodSignature = getMethodSignature();
MethodAccessFlags accessFlags = getAccessFlags();
+ Code code = accessFlags.isAbstract() ? null : getCodeObject(methodSignature);
DexEncodedMethod method =
- new DexEncodedMethod(
- methodSignature,
- accessFlags,
- genericSignature,
- annotations,
- parameterAnnotationsList,
- accessFlags.isAbstract() ? null : getCodeObject(methodSignature),
- isCompilerSynthesized,
- classFileVersion,
- AndroidApiLevel.UNKNOWN,
- AndroidApiLevel.UNKNOWN);
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(methodSignature)
+ .setAccessFlags(accessFlags)
+ .setGenericSignature(genericSignature)
+ .setAnnotations(annotations)
+ .setParameterAnnotations(parameterAnnotationsList)
+ .setCode(code)
+ .setClassFileVersion(classFileVersion)
+ .setApiLevelForDefinition(AndroidApiLevel.UNKNOWN)
+ .setApiLevelForCode(AndroidApiLevel.UNKNOWN)
+ .build();
assert isValidSyntheticMethod(method, syntheticKind);
if (onBuildConsumer != null) {
onBuildConsumer.accept(method);
diff --git a/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java b/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java
index 7259af1..4f652cf 100644
--- a/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java
@@ -19,6 +19,12 @@
return curry(function).apply(arg);
}
+ public static <T> void acceptIfNotNull(T element, Consumer<T> consumer) {
+ if (element != null) {
+ consumer.accept(element);
+ }
+ }
+
public static <T> Consumer<T> acceptIfNotSeen(Consumer<T> consumer, Set<T> seen) {
return element -> {
if (seen.add(element)) {
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 e0a5e76..7837852 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -307,7 +307,13 @@
public int classInliningInstructionLimit = 10;
public int classInliningInstructionAllowance = 50;
// This defines the limit of instructions in the inlinee
- public int inliningInstructionLimit = 3;
+ public int inliningInstructionLimit =
+ !Version.isDevelopmentVersion()
+ ? 3
+ : System.getProperty("com.android.tools.r8.inliningInstructionLimit") != null
+ ? Integer.parseInt(
+ System.getProperty("com.android.tools.r8.inliningInstructionLimit"))
+ : 3;
// This defines how many instructions of inlinees we can inlinee overall.
public int inliningInstructionAllowance = 1500;
// Maximum number of distinct values in a method that may be used in a monitor-enter instruction.
@@ -1212,12 +1218,12 @@
private final int maxNumberOfDispatchTargetsBeforeAbandoning = 10;
// TODO(b/69963623): enable if everything is ready, including signature rewriting at call sites.
- private boolean enableConstantPropagation = false;
+ private boolean enableLegacyConstantPropagation = false;
private boolean enableExperimentalArgumentPropagation = false;
private boolean enableDynamicTypePropagation = true;
public void disableOptimization() {
- enableConstantPropagation = false;
+ enableLegacyConstantPropagation = false;
enableDynamicTypePropagation = false;
}
@@ -1233,7 +1239,7 @@
if (!isOptimizing()) {
return false;
}
- return enableConstantPropagation || enableDynamicTypePropagation;
+ return enableLegacyConstantPropagation || enableDynamicTypePropagation;
}
public boolean isExperimentalArgumentPropagationEnabled() {
@@ -1241,16 +1247,17 @@
}
public boolean isConstantPropagationEnabled() {
- return enableConstantPropagation;
+ return enableLegacyConstantPropagation || isExperimentalArgumentPropagationEnabled();
}
public boolean isDynamicTypePropagationEnabled() {
return enableDynamicTypePropagation;
}
- public void setEnableConstantPropagation() {
+ public CallSiteOptimizationOptions setEnableLegacyConstantPropagation() {
assert !isConstantPropagationEnabled();
- enableConstantPropagation = true;
+ enableLegacyConstantPropagation = true;
+ return this;
}
public CallSiteOptimizationOptions setEnableExperimentalArgumentPropagation(
@@ -1260,13 +1267,6 @@
}
}
- // TODO(b/69963623): Remove this once enabled.
- @VisibleForTesting
- public static void enableConstantArgumentPropagationForTesting(InternalOptions options) {
- assert !options.callSiteOptimizationOptions().isConstantPropagationEnabled();
- options.callSiteOptimizationOptions().enableConstantPropagation = true;
- }
-
public class HorizontalClassMergerOptions {
// TODO(b/138781768): Set enable to true when this bug is resolved.
diff --git a/src/main/java/com/android/tools/r8/utils/SetUtils.java b/src/main/java/com/android/tools/r8/utils/SetUtils.java
index bd97bd7..04b399d 100644
--- a/src/main/java/com/android/tools/r8/utils/SetUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/SetUtils.java
@@ -10,6 +10,7 @@
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
public class SetUtils {
@@ -23,6 +24,10 @@
return false;
}
+ public static <T> Set<T> newConcurrentHashSet(int capacity) {
+ return Collections.newSetFromMap(new ConcurrentHashMap<>(capacity));
+ }
+
public static <T> HashSet<T> newHashSet(T element) {
HashSet<T> result = new HashSet<>(1);
result.add(element);
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
index 5122253..b6f7c52 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
@@ -94,6 +94,10 @@
return backing.contains(signature);
}
+ public boolean contains(DexEncodedMethod method) {
+ return contains(method.getSignature());
+ }
+
public boolean contains(DexClassAndMethod method) {
return contains(method.getMethodSignature());
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
index 5152dde..7687a88 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
@@ -10,70 +10,133 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.Sets;
+import com.android.tools.r8.utils.SetUtils;
import java.util.Set;
import java.util.function.IntFunction;
public class LongLivedProgramMethodSetBuilder<T extends ProgramMethodSet> {
+ // Factory for creating the final ProgramMethodSet.
private final IntFunction<T> factory;
- private final Set<DexMethod> methods;
- private LongLivedProgramMethodSetBuilder(IntFunction<T> factory, Set<DexMethod> methods) {
+ // Factory for creating a Set<DexMethod>.
+ private final IntFunction<Set<DexMethod>> factoryForBuilder;
+
+ // The graph lens that this collection has been rewritten up until.
+ private GraphLens appliedGraphLens;
+
+ // The methods in this collection.
+ private Set<DexMethod> methods;
+
+ private LongLivedProgramMethodSetBuilder(
+ GraphLens currentGraphLens,
+ IntFunction<T> factory,
+ IntFunction<Set<DexMethod>> factoryBuilder) {
+ this.appliedGraphLens = currentGraphLens;
this.factory = factory;
- this.methods = methods;
+ this.factoryForBuilder = factoryBuilder;
+ this.methods = factoryBuilder.apply(2);
}
- public static LongLivedProgramMethodSetBuilder<?> createForIdentitySet() {
+ public static LongLivedProgramMethodSetBuilder<ProgramMethodSet> createForIdentitySet(
+ GraphLens currentGraphLens) {
return new LongLivedProgramMethodSetBuilder<>(
- ProgramMethodSet::create, Sets.newIdentityHashSet());
+ currentGraphLens, ProgramMethodSet::create, SetUtils::newIdentityHashSet);
}
- public static LongLivedProgramMethodSetBuilder<SortedProgramMethodSet> createForSortedSet() {
+ public static LongLivedProgramMethodSetBuilder<ProgramMethodSet> createConcurrentForIdentitySet(
+ GraphLens currentGraphLens) {
return new LongLivedProgramMethodSetBuilder<>(
- ignore -> SortedProgramMethodSet.create(), Sets.newIdentityHashSet());
+ currentGraphLens, ProgramMethodSet::create, SetUtils::newConcurrentHashSet);
}
- public static LongLivedProgramMethodSetBuilder<?> createConcurrentForIdentitySet() {
- return new LongLivedProgramMethodSetBuilder<>(
- ignore -> ProgramMethodSet.create(), Sets.newConcurrentHashSet());
- }
-
+ @Deprecated
public void add(ProgramMethod method) {
methods.add(method.getReference());
}
- public void addAll(Iterable<ProgramMethod> methods) {
- methods.forEach(this::add);
+ public void add(ProgramMethod method, GraphLens currentGraphLens) {
+ // All methods in a long lived program method set should be rewritten up until the same graph
+ // lens.
+ assert verifyIsRewrittenWithLens(currentGraphLens);
+ methods.add(method.getReference());
+ }
+
+ public void addAll(Iterable<ProgramMethod> methodsToAdd, GraphLens currentGraphLens) {
+ assert verifyIsRewrittenWithLens(currentGraphLens);
+ methodsToAdd.forEach(method -> methods.add(method.getReference()));
+ }
+
+ public void clear() {
+ methods.clear();
+ }
+
+ public boolean contains(ProgramMethod method, GraphLens currentGraphLens) {
+ // We can only query a long lived program method set that is fully lens rewritten.
+ assert verifyIsRewrittenWithLens(currentGraphLens);
+ return methods.contains(method.getReference());
+ }
+
+ public boolean isRewrittenWithLens(GraphLens graphLens) {
+ return appliedGraphLens == graphLens;
+ }
+
+ public LongLivedProgramMethodSetBuilder<T> merge(LongLivedProgramMethodSetBuilder<T> builder) {
+ // Check that the two builders are rewritten up until the same lens (if not we could rewrite the
+ // methods in the given builder up until the applied graph lens of this builder, but it must be
+ // such that this builder has the same or a newer graph lens than the given builder).
+ if (isRewrittenWithLens(builder.appliedGraphLens)) {
+ methods.addAll(builder.methods);
+ } else {
+ // Rewrite the methods in the given builder up until the applied graph lens of this builder.
+ // Note that this builder must have a newer graph lens than the given builder.
+ assert verifyIsRewrittenWithNewerLens(builder.appliedGraphLens);
+ for (DexMethod method : builder.methods) {
+ methods.add(appliedGraphLens.getRenamedMethodSignature(method, builder.appliedGraphLens));
+ }
+ }
+ return this;
}
public void remove(DexMethod method) {
methods.remove(method);
}
- public void removeAll(Iterable<DexMethod> methods) {
+ public LongLivedProgramMethodSetBuilder<T> removeAll(Iterable<DexMethod> methods) {
methods.forEach(this::remove);
+ return this;
}
- public void rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens applied) {
- Set<DexMethod> newMethods = Sets.newIdentityHashSet();
- for (DexMethod method : methods) {
- newMethods.add(appView.graphLens().getRenamedMethodSignature(method, applied));
+ public LongLivedProgramMethodSetBuilder<T> rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView) {
+ return rewrittenWithLens(appView.graphLens());
+ }
+
+ public LongLivedProgramMethodSetBuilder<T> rewrittenWithLens(GraphLens newGraphLens) {
+ // Check if the graph lens has changed (otherwise lens rewriting is not needed).
+ if (newGraphLens == appliedGraphLens) {
+ return this;
}
- methods.clear();
- methods.addAll(newMethods);
+
+ // Rewrite the backing.
+ Set<DexMethod> newMethods = factoryForBuilder.apply(methods.size());
+ for (DexMethod method : methods) {
+ newMethods.add(newGraphLens.getRenamedMethodSignature(method, appliedGraphLens));
+ }
+ methods = newMethods;
+
+ // Record that this collection is now rewritten up until the given graph lens.
+ appliedGraphLens = newGraphLens;
+ return this;
}
public T build(AppView<AppInfoWithLiveness> appView) {
- return build(appView, null);
- }
-
- public T build(AppView<AppInfoWithLiveness> appView, GraphLens appliedGraphLens) {
T result = factory.apply(methods.size());
- for (DexMethod oldMethod : methods) {
- DexMethod method = appView.graphLens().getRenamedMethodSignature(oldMethod, appliedGraphLens);
- DexProgramClass holder = appView.definitionForHolder(method).asProgramClass();
- result.createAndAdd(holder, holder.lookupMethod(method));
+ for (DexMethod method : methods) {
+ DexMethod rewrittenMethod =
+ appView.graphLens().getRenamedMethodSignature(method, appliedGraphLens);
+ DexProgramClass holder = appView.definitionForHolder(rewrittenMethod).asProgramClass();
+ result.createAndAdd(holder, holder.lookupMethod(rewrittenMethod));
}
return result;
}
@@ -81,4 +144,18 @@
public boolean isEmpty() {
return methods.isEmpty();
}
+
+ public boolean verifyIsRewrittenWithLens(GraphLens graphLens) {
+ assert isRewrittenWithLens(graphLens);
+ return true;
+ }
+
+ public boolean verifyIsRewrittenWithNewerLens(GraphLens graphLens) {
+ assert appliedGraphLens != graphLens;
+ assert appliedGraphLens.isNonIdentityLens();
+ assert graphLens.isIdentityLens()
+ || appliedGraphLens.asNonIdentityLens().findPrevious(previous -> previous == graphLens)
+ != null;
+ return true;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
index 0637a0b..2a8f1bb 100644
--- a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
+++ b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
@@ -1,6 +1,7 @@
package com.android.tools.r8;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.fail;
@@ -8,6 +9,7 @@
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.List;
import org.junit.Test;
@@ -92,15 +94,10 @@
diagnostics -> {
diagnostics.assertErrorsMatch(
diagnosticMessage(containsString("java.util.concurrent.Flow$Subscriber")));
- if (parameters.isCfRuntime()) {
- diagnostics.assertOnlyErrors();
- } else {
- // TODO(b/198368663): R8 will double report missing classes in itf desugaring.
- diagnostics.assertWarningsMatch(
- diagnosticMessage(containsString("java.util.concurrent.Flow$Subscriber")));
- diagnostics.assertErrorsCount(1);
- diagnostics.assertWarningsCount(1);
- diagnostics.assertInfosCount(0);
+ diagnostics.assertOnlyErrors();
+ if (parameters.isDexRuntime()) {
+ // TODO(b/175659048): This should likely be a desugar diagnostic.
+ diagnostics.assertErrorsMatch(diagnosticType(MissingDefinitionsDiagnostic.class));
}
});
} catch (CompilationFailedException e) {
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index f92a490..718cf4d 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -158,7 +158,8 @@
return self();
}
- public JvmTestBuilder enableJaCoCoAgentForOfflineInstrumentedCode(Path jacocoAgent, Path output) {
+ public JvmTestBuilder configureJaCoCoAgentForOfflineInstrumentedCode(
+ Path jacocoAgent, Path output) {
addProgramFiles(jacocoAgent);
addVmArguments(
"-Djacoco-agent.destfile=" + output.toString(),
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaDontPublicize.java b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaDontPublicize.java
new file mode 100644
index 0000000..cc9d06b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaDontPublicize.java
@@ -0,0 +1,85 @@
+// 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.desugar;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DesugarTestConfiguration;
+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.ClassOrMemberSubject;
+import java.util.ArrayList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DesugarLambdaDontPublicize extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ private final TestParameters parameters;
+
+ public DesugarLambdaDontPublicize(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testDesugar() throws Exception {
+ testForDesugaring(parameters)
+ .addInnerClasses(DesugarLambdaDontPublicize.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("foobar")
+ .inspectIf(
+ DesugarTestConfiguration::isDesugared,
+ inspector -> {
+ // Ensure that we don't add an extra public method for the lambda call.
+ // Mockito will potentially mock this, see: b/195402351
+ long count =
+ inspector.clazz(TestClass.class).allMethods().stream()
+ .filter(ClassOrMemberSubject::isPublic)
+ .count();
+ assertEquals(count, 3);
+ });
+ }
+
+ public static class StringList extends ArrayList<String> {
+ public void forEachString(MyConsumer<String> consumer) {
+ for (String s : this) {
+ consumer.accept(s);
+ }
+ }
+ }
+
+ public interface MyConsumer<T> {
+ void accept(T s);
+ }
+
+ public static class TestClass {
+
+ public void test() {
+ StringList list = new StringList();
+
+ list.add("foobar");
+ list.forEachString(
+ s -> {
+ class MyConsumerImpl implements MyConsumer<String> {
+ public void accept(String s) {
+ System.out.println(s);
+ }
+ }
+ new MyConsumerImpl().accept(s);
+ });
+ }
+
+ public static void main(String[] args) {
+ new TestClass().test();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
index 86fad6d..266745e 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
@@ -81,13 +81,6 @@
.run(parameters.getRuntime(), MAIN_CLASS)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
- // Run instrumented code without an agent.
- testForRuntime(parameters)
- .addProgramFiles(testClasses.getInstrumented())
- .addProgramFiles(ToolHelper.JACOCO_AGENT)
- .run(parameters.getRuntime(), MAIN_CLASS)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
-
// Run non-instrumented code with an agent causing on the fly instrumentation on the JVM.
Path output = temp.newFolder().toPath();
Path agentOutputOnTheFly = output.resolve("on-the-fly");
@@ -99,11 +92,11 @@
List<String> onTheFlyReport = testClasses.generateReport(agentOutputOnTheFly);
assertEquals(2, onTheFlyReport.size());
- // Run the instrumented code with offline instrumentation turned on.
+ // Run the instrumented code.
Path agentOutputOffline = output.resolve("offline");
testForJvm()
.addProgramFiles(testClasses.getInstrumented())
- .enableJaCoCoAgentForOfflineInstrumentedCode(ToolHelper.JACOCO_AGENT, agentOutputOffline)
+ .configureJaCoCoAgentForOfflineInstrumentedCode(ToolHelper.JACOCO_AGENT, agentOutputOffline)
.run(parameters.getRuntime(), MAIN_CLASS)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
List<String> offlineReport = testClasses.generateReport(agentOutputOffline);
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 640796d..31f87d9 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,6 +102,7 @@
.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/dex/JumboStringProcessing.java b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
index e5b4c08..afc7a62 100644
--- a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
+++ b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
@@ -17,16 +17,13 @@
import com.android.tools.r8.code.IfNez;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
@@ -155,13 +152,11 @@
DexCode code = new DexCode(1, 0, 0, instructions, new Try[0], new TryHandler[0], null);
MethodAccessFlags flags = MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, false);
DexEncodedMethod method =
- new DexEncodedMethod(
- null,
- flags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code);
+ DexEncodedMethod.builder()
+ .setAccessFlags(flags)
+ .setCode(code)
+ .disableMethodNotNullCheck()
+ .build();
return new JumboStringRewriter(method, string, factory).rewrite();
}
}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
index ddef0b4..b0be3f7 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
import org.junit.Test;
public class ArgumentInfoCollectionTest extends TestBase {
@@ -49,13 +50,22 @@
@Test
public void testCombineRemoved() {
DexItemFactory factory = new DexItemFactory();
+ AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
// Arguments removed: 0 1 2 3 4 -> 0 2 4.
ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
builder1.addArgumentInfo(
- 1, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ 1,
+ RemovedArgumentInfo.builder()
+ .setType(factory.intType)
+ .setSingleValue(abstractValueFactory.createNullValue())
+ .build());
builder1.addArgumentInfo(
- 3, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ 3,
+ RemovedArgumentInfo.builder()
+ .setType(factory.intType)
+ .setSingleValue(abstractValueFactory.createNullValue())
+ .build());
ArgumentInfoCollection arguments1 = builder1.build();
// Arguments removed: 0 2 4 -> 0. Arguments 2 and 4 are at position 1 and 2 after first removal.
@@ -69,27 +79,36 @@
RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
assertEquals(arg1.getType(), factory.intType);
- assertTrue(arg1.isAlwaysNull());
+ assertTrue(arg1.hasSingleValue());
RemovedArgumentInfo arg2 = combine.getArgumentInfo(2).asRemovedArgumentInfo();
assertEquals(arg2.getType(), factory.doubleType);
- assertFalse(arg2.isAlwaysNull());
+ assertFalse(arg2.hasSingleValue());
RemovedArgumentInfo arg3 = combine.getArgumentInfo(3).asRemovedArgumentInfo();
assertEquals(arg3.getType(), factory.intType);
- assertTrue(arg3.isAlwaysNull());
+ assertTrue(arg3.hasSingleValue());
RemovedArgumentInfo arg4 = combine.getArgumentInfo(4).asRemovedArgumentInfo();
assertEquals(arg4.getType(), factory.doubleType);
- assertFalse(arg4.isAlwaysNull());
+ assertFalse(arg4.hasSingleValue());
}
@Test
public void testCombineRemoveRewritten() {
DexItemFactory factory = new DexItemFactory();
+ AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
builder1.addArgumentInfo(
- 1, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ 1,
+ RemovedArgumentInfo.builder()
+ .setType(factory.intType)
+ .setSingleValue(abstractValueFactory.createNullValue())
+ .build());
builder1.addArgumentInfo(
- 3, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ 3,
+ RemovedArgumentInfo.builder()
+ .setType(factory.intType)
+ .setSingleValue(abstractValueFactory.createNullValue())
+ .build());
ArgumentInfoCollection arguments1 = builder1.build();
ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
@@ -101,13 +120,13 @@
RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
assertEquals(arg1.getType(), factory.intType);
- assertTrue(arg1.isAlwaysNull());
+ assertTrue(arg1.hasSingleValue());
RewrittenTypeInfo arg2 = combine.getArgumentInfo(2).asRewrittenTypeInfo();
assertEquals(arg2.getOldType(), factory.floatType);
assertEquals(arg2.getNewType(), factory.doubleType);
RemovedArgumentInfo arg3 = combine.getArgumentInfo(3).asRemovedArgumentInfo();
assertEquals(arg3.getType(), factory.intType);
- assertTrue(arg3.isAlwaysNull());
+ assertTrue(arg3.hasSingleValue());
RewrittenTypeInfo arg4 = combine.getArgumentInfo(4).asRewrittenTypeInfo();
assertEquals(arg4.getOldType(), factory.floatType);
assertEquals(arg4.getNewType(), factory.doubleType);
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
index 4e41e64..d8e2db4 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
@@ -13,9 +13,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CallGraph.Node;
import com.android.tools.r8.origin.SynthesizedOrigin;
@@ -53,13 +51,11 @@
ProgramMethod method =
new ProgramMethod(
clazz,
- new DexEncodedMethod(
- signature,
- MethodAccessFlags.fromDexAccessFlags(0),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- null));
+ DexEncodedMethod.builder()
+ .setMethod(signature)
+ .setAccessFlags(MethodAccessFlags.fromDexAccessFlags(0))
+ .setCode(null)
+ .build());
return new Node(method);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
index 4b220b6..70d3f3b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
@@ -5,6 +5,7 @@
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.NeverClassInline;
@@ -15,7 +16,6 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -51,16 +51,20 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeDirectPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableNeverClassInliningAnnotations()
- .enableInliningAnnotations()
.addOptionsModification(
o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ if (!enableExperimentalArgumentPropagation) {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ }
o.callSiteOptimizationOptions()
+ .setEnableLegacyConstantPropagation()
.setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
})
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
+ .minification(!enableExperimentalArgumentPropagation)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null")
.inspect(this::inspect);
@@ -79,8 +83,20 @@
private void inspect(CodeInspector inspector) {
ClassSubject main = inspector.clazz(MAIN);
assertThat(main, isPresent());
+
+ if (enableExperimentalArgumentPropagation) {
+ // Verify that the "nul" argument has been propagated to the test() method.
+ MethodSubject mainMethodSubject = main.mainMethod();
+ assertThat(mainMethodSubject, isPresent());
+ assertTrue(
+ mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
+ }
+
MethodSubject test = main.uniqueMethodWithName("test");
assertThat(test, isPresent());
+ assertEquals(
+ 1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
+ test.getProgramMethod().getReference().getArity());
// Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
assertTrue(test.streamInstructions().noneMatch(InstructionSubject::isIf));
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
index 553ee4b..5612674 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
@@ -5,6 +5,7 @@
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.NeverClassInline;
@@ -16,7 +17,6 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -52,19 +52,23 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfacePositiveTest.class)
.addKeepMainRule(MAIN)
- .enableNeverClassInliningAnnotations()
- .enableInliningAnnotations()
- .enableNoHorizontalClassMergingAnnotations()
- .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.addOptionsModification(
o -> {
// To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
// target.
o.enableDevirtualization = false;
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ if (!enableExperimentalArgumentPropagation) {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ }
o.callSiteOptimizationOptions()
+ .setEnableLegacyConstantPropagation()
.setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
})
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .enableNoHorizontalClassMergingAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
+ .minification(!enableExperimentalArgumentPropagation)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null")
@@ -83,18 +87,45 @@
}
private void inspect(CodeInspector inspector) {
+ ClassSubject main = inspector.clazz(MAIN);
+ assertThat(main, isPresent());
+
+ if (enableExperimentalArgumentPropagation) {
+ // Verify that the "nul" argument has been propagated to the m() methods.
+ MethodSubject mainMethodSubject = main.mainMethod();
+ assertThat(mainMethodSubject, isPresent());
+ assertTrue(
+ mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
+ }
+
ClassSubject i = inspector.clazz(I.class);
assertThat(i, isPresent());
+
+ MethodSubject i_m = i.uniqueMethodWithName("m");
+ assertThat(i_m, isPresent());
+ assertEquals(
+ 1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
+ i_m.getProgramMethod().getReference().getArity());
+
ClassSubject a = inspector.clazz(A.class);
assertThat(a, isPresent());
+
MethodSubject a_m = a.uniqueMethodWithName("m");
assertThat(a_m, isPresent());
+ assertEquals(
+ 1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
+ a_m.getProgramMethod().getReference().getArity());
// Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
assertTrue(a_m.streamInstructions().noneMatch(InstructionSubject::isIf));
+
ClassSubject b = inspector.clazz(B.class);
assertThat(b, isPresent());
+
MethodSubject b_m = b.uniqueMethodWithName("m");
assertThat(b_m, isPresent());
+ assertEquals(
+ 1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
+ b_m.getProgramMethod().getReference().getArity());
// Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
assertTrue(b_m.streamInstructions().noneMatch(InstructionSubject::isIf));
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
index fe38d71..3f9baaa 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
@@ -5,6 +5,7 @@
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;
@@ -14,7 +15,6 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -50,15 +50,19 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeStaticPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableInliningAnnotations()
.addOptionsModification(
o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ if (!enableExperimentalArgumentPropagation) {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ }
o.callSiteOptimizationOptions()
+ .setEnableLegacyConstantPropagation()
.setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
})
+ .enableInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
+ .minification(!enableExperimentalArgumentPropagation)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null")
.inspect(this::inspect);
@@ -78,8 +82,20 @@
private void inspect(CodeInspector inspector) {
ClassSubject main = inspector.clazz(MAIN);
assertThat(main, isPresent());
+
+ if (enableExperimentalArgumentPropagation) {
+ // Verify that the "nul" argument has been propagated to the test() method.
+ MethodSubject mainMethodSubject = main.mainMethod();
+ assertThat(mainMethodSubject, isPresent());
+ assertTrue(
+ mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
+ }
+
MethodSubject test = main.uniqueMethodWithName("test");
assertThat(test, isPresent());
+ assertEquals(
+ 1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
+ test.getProgramMethod().getReference().getArity());
// Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
assertTrue(test.streamInstructions().noneMatch(InstructionSubject::isIf));
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
index 9853a4c..f3b3324 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -51,17 +50,17 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableNoVerticalClassMergingAnnotations()
- .enableNeverClassInliningAnnotations()
- .enableInliningAnnotations()
.addOptionsModification(
o -> {
o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
o.callSiteOptimizationOptions()
+ .setEnableLegacyConstantPropagation()
.setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
})
+ .enableNoVerticalClassMergingAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("non-null", "null")
.inspect(this::inspect);
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
new file mode 100644
index 0000000..0c0bac6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOptimize.java
@@ -0,0 +1,47 @@
+// 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 0005549..c6182b5 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -47,11 +47,9 @@
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.IRCode;
@@ -856,13 +854,11 @@
new SynthesizedCode(
(ignored, callerPosition) -> new ReturnVoidCode(voidReturnMethod, callerPosition));
DexEncodedMethod method =
- new DexEncodedMethod(
- voidReturnMethod,
- access,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code);
+ DexEncodedMethod.builder()
+ .setMethod(voidReturnMethod)
+ .setAccessFlags(access)
+ .setCode(code)
+ .build();
ProgramMethod programMethod = new ProgramMethod(programClass, method);
IRCode ir = code.buildIR(programMethod, appView, Origin.unknown());
RegisterAllocator allocator = new LinearScanRegisterAllocator(appView, ir);
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 bcea2fe..42cd647 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -391,6 +391,7 @@
.setMinApi(minSdk)
.noMinification()
.noTreeShaking()
+ .addDontOptimize()
.setMainDexListConsumer(ToolHelper.consumeString(r8MainDexListOutput::set))
.allowDiagnosticMessages()
.compileWithExpectedDiagnostics(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java
new file mode 100644
index 0000000..7b7589b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java
@@ -0,0 +1,94 @@
+// 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 junit.framework.TestCase.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+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 ConstantUnboxedEnumArgumentTest 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::isStaticGet));
+
+ MethodSubject testMethodSubject = mainClassSubject.uniqueMethodWithName("test");
+ assertThat(testMethodSubject, isPresent());
+ assertEquals(0, testMethodSubject.getProgramMethod().getReference().getArity());
+ assertTrue(
+ testMethodSubject
+ .streamInstructions()
+ .anyMatch(instruction -> instruction.isConstString("A")));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ // Argument should be removed by argument propagation.
+ test(MyEnum.A);
+ }
+
+ @NeverInline
+ static void test(MyEnum myEnum) {
+ // Argument propagation should remove the parameter `myEnum` and materialize an access to
+ // `MyEnum.A`, which should subsequently be rewritten by enum unboxing.
+ System.out.println(myEnum.name());
+ }
+ }
+
+ enum MyEnum {
+ A
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
index 9b246e1..e1c2d9b 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -41,13 +40,13 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> {
- CallSiteOptimizationOptions callSiteOptimizationOptions =
- options.callSiteOptimizationOptions();
- callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(true);
- callSiteOptimizationOptions.setEnableConstantPropagation();
- })
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(true))
.enableInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
+ .noMinification()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(
@@ -58,8 +57,7 @@
// The test() method has been optimized.
MethodSubject testMethodSubject = mainClassSubject.uniqueMethodWithName("test");
assertThat(testMethodSubject, isPresent());
- // TODO(b/190154391): The parameter x should be removed.
- assertEquals(1, testMethodSubject.getProgramMethod().getParameters().size());
+ assertEquals(0, testMethodSubject.getProgramMethod().getParameters().size());
assertTrue(
testMethodSubject.streamInstructions().noneMatch(InstructionSubject::isIf));
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
index 45cd552..ae1d888 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -41,13 +40,13 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> {
- CallSiteOptimizationOptions callSiteOptimizationOptions =
- options.callSiteOptimizationOptions();
- callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(true);
- callSiteOptimizationOptions.setEnableConstantPropagation();
- })
+ options ->
+ options
+ .callSiteOptimizationOptions()
+ .setEnableExperimentalArgumentPropagation(true))
.enableInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
+ .noMinification()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(
@@ -59,8 +58,7 @@
for (int i = 1; i <= 3; i++) {
MethodSubject testMethodSubject = mainClassSubject.uniqueMethodWithName("test" + i);
assertThat(testMethodSubject, isPresent());
- // TODO(b/190154391): The parameter x should be removed.
- assertEquals(1, testMethodSubject.getProgramMethod().getParameters().size());
+ assertEquals(0, testMethodSubject.getProgramMethod().getParameters().size());
assertTrue(
testMethodSubject.streamInstructions().noneMatch(InstructionSubject::isIf));
}
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java
new file mode 100644
index 0000000..e5f64cf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java
@@ -0,0 +1,93 @@
+// 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 junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+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 UnboxedEnumUserInMethodWithConstantArgumentTest 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::isConstNumber));
+
+ MethodSubject testMethodSubject = mainClassSubject.uniqueMethodWithName("test");
+ assertThat(testMethodSubject, isPresent());
+ assertEquals(0, testMethodSubject.getProgramMethod().getReference().getArity());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ test(true);
+ }
+
+ @NeverInline
+ static void test(boolean alwaysTrue) {
+ if (alwaysTrue) {
+ // Failure to reprocess this method after the unboxing of MyEnum will lead to runtime
+ // errors.
+ MyEnum myEnum = System.currentTimeMillis() > 0 ? MyEnum.A : MyEnum.B;
+ System.out.println(myEnum.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 252dcc5..d68447d 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -105,6 +105,7 @@
.addKeepMainRule(Main.class)
.addKeepPackageNamesRule(getClass().getPackage())
.noTreeShaking()
+ .addDontOptimize()
.addKeepAttributeSourceFile()
.addKeepAttributeLineNumberTable()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java
index df7c599..6d9c328 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiBinaryCompatibilityTest.java
@@ -63,8 +63,10 @@
assertNotEquals(0, existing.size());
for (Path classFile : generated) {
Path otherClassFile = binaryContents.resolve(generatedContents.relativize(classFile));
- assertTrue(Files.exists(otherClassFile));
- assertTrue(TestBase.filesAreEqual(classFile, otherClassFile));
+ assertTrue("Could not find file: " + otherClassFile, Files.exists(otherClassFile));
+ assertTrue(
+ "Non-equal files: " + otherClassFile,
+ TestBase.filesAreEqual(classFile, otherClassFile));
}
}
}
@@ -75,10 +77,12 @@
@Test
public void runCheckedInBinaryJar() throws Exception {
+ // The retrace jar is only built when building r8lib.
+ Path jar = ToolHelper.isTestingR8Lib() ? ToolHelper.R8_RETRACE_JAR : ToolHelper.R8_JAR;
for (CfRuntime cfRuntime : CfRuntime.getCheckedInCfRuntimes()) {
RetraceApiTestHelper.runJunitOnTests(
cfRuntime,
- ToolHelper.R8_RETRACE_JAR,
+ jar,
BINARY_COMPATIBILITY_JAR,
RetraceApiTestHelper.getBinaryCompatibilityTests());
}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
index 9b2f67d..7f9834b 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
@@ -63,13 +63,13 @@
classPaths,
"org.junit.runner.JUnitCore",
StringUtils.join(" ", tests, Class::getTypeName));
- assertEquals(0, processResult.exitCode);
+ assertEquals(processResult.toString(), 0, processResult.exitCode);
assertThat(processResult.stdout, containsString("OK (" + tests.size() + " test"));
}
private static Path getJunitDependency() {
String junitPath =
- Arrays.stream(System.getProperty("java.class.path").split(":"))
+ Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator))
.filter(cp -> cp.endsWith(JUNIT_JAR))
.collect(Collectors.toSingle());
return Paths.get(junitPath);
@@ -77,7 +77,7 @@
private static Path getHamcrest() {
String junitPath =
- Arrays.stream(System.getProperty("java.class.path").split(":"))
+ Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator))
.filter(cp -> cp.endsWith(HAMCREST))
.collect(Collectors.toSingle());
return Paths.get(junitPath);
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 21501d0..c9d30fd 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -85,6 +85,8 @@
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.
diff --git a/tools/r8_release.py b/tools/r8_release.py
index bf98dd3..0446d64 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -15,7 +15,7 @@
import utils
-R8_DEV_BRANCH = '3.1'
+R8_DEV_BRANCH = '3.2'
R8_VERSION_FILE = os.path.join(
'src', 'main', 'java', 'com', 'android', 'tools', 'r8', 'Version.java')
THIS_FILE_RELATIVE = os.path.join('tools', 'r8_release.py')