Remove EnumValueInfoMap uses in enum unboxer
Bug: 172528424
Bug: 160939354
Change-Id: Ieace568931216a114908549e28d78378727d6ea4
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5521ef9..dc81ff4 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -33,7 +33,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.DirectMappedDexApplication.Builder;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -626,10 +625,6 @@
// TODO: we should avoid removing liveness.
Set<DexType> prunedTypes = appView.withLiveness().appInfo().getPrunedTypes();
- // TODO: move to appview.
- EnumValueInfoMapCollection enumValueInfoMapCollection =
- appViewWithLiveness.appInfo().getEnumValueInfoMapCollection();
-
timing.begin("Create IR");
CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
try {
@@ -729,13 +724,11 @@
missingClasses,
prunedTypes);
appView.setAppInfo(
- enqueuer
- .traceApplication(
- appView.rootSet(),
- options.getProguardConfiguration().getDontWarnPatterns(),
- executorService,
- timing)
- .withEnumValueInfoMaps(enumValueInfoMapCollection));
+ enqueuer.traceApplication(
+ appView.rootSet(),
+ options.getProguardConfiguration().getDontWarnPatterns(),
+ executorService,
+ timing));
// Rerunning the enqueuer should not give rise to any method rewritings.
assert enqueuer.buildGraphLens() == null;
appView.withGeneratedMessageLiteBuilderShrinker(
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 dd13c7d..8e0800b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.conversion.MethodProcessingId;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
import com.android.tools.r8.ir.optimize.CallSiteOptimizationInfoPropagator;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
import com.android.tools.r8.ir.optimize.library.LibraryMemberOptimizer;
import com.android.tools.r8.ir.optimize.library.LibraryMethodSideEffectModelCollection;
@@ -85,7 +86,7 @@
private HorizontallyMergedClasses horizontallyMergedClasses;
private StaticallyMergedClasses staticallyMergedClasses;
private VerticallyMergedClasses verticallyMergedClasses;
- private EnumValueInfoMapCollection unboxedEnums = EnumValueInfoMapCollection.empty();
+ private EnumDataMap unboxedEnums = EnumDataMap.empty();
// TODO(b/169115389): Remove
private Set<DexMethod> cfByteCodePassThrough = ImmutableSet.of();
@@ -510,18 +511,18 @@
testing().verticallyMergedClassesConsumer.accept(dexItemFactory(), verticallyMergedClasses);
}
- public EnumValueInfoMapCollection unboxedEnums() {
+ public EnumDataMap unboxedEnums() {
return unboxedEnums;
}
- public void setUnboxedEnums(EnumValueInfoMapCollection unboxedEnums) {
+ public void setUnboxedEnums(EnumDataMap unboxedEnums) {
assert this.unboxedEnums.isEmpty();
this.unboxedEnums = unboxedEnums;
testing().unboxedEnumsConsumer.accept(dexItemFactory(), unboxedEnums);
}
public boolean validateUnboxedEnumsHaveBeenPruned() {
- for (DexType unboxedEnum : unboxedEnums.enumSet()) {
+ for (DexType unboxedEnum : unboxedEnums.getUnboxedEnums()) {
assert appInfo.definitionForWithoutExistenceAssert(unboxedEnum) == null
: "Enum " + unboxedEnum + " has been unboxed but is still in the program.";
assert appInfo().withLiveness().wasPruned(unboxedEnum)
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
index 8a02e12..b2dcdcd 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
@@ -95,41 +95,22 @@
return this;
}
- // We need to access the enum instance object state to figure out if it contains known constant
- // field values. The enum instance may be accessed in two ways, directly through the enum
- // static field, or through the enum $VALUES field. If none of them are kept, the instance is
- // effectively unused. The object state may be stored in the enum static field optimization
- // info, if kept, or in the $VALUES optimization info, if kept.
- // If the enum instance is unused, this method answers null.
- public ObjectState getObjectStateForPossiblyPinnedEnumInstance(DexField field, int ordinal) {
-
- // Attempt 1: Get object state from the instance field's optimization info.
+ public ObjectState getObjectStateForPossiblyPinnedField(DexField field) {
AbstractValue fieldValue = enumAbstractValues.get(field);
- if (fieldValue != null) {
- if (fieldValue.isSingleFieldValue()) {
- return fieldValue.asSingleFieldValue().getState();
- }
- if (fieldValue.isUnknown()) {
- return ObjectState.empty();
- }
- assert fieldValue.isZero();
- }
-
- // Attempt 2: Get object state from the values field's optimization info.
- if (valuesAbstractValue.isZero()) {
- // Unused enum instance.
+ if (fieldValue == null || fieldValue.isZero()) {
return null;
}
- if (valuesAbstractValue.isUnknown()) {
- return ObjectState.empty();
+ if (fieldValue.isSingleFieldValue()) {
+ return fieldValue.asSingleFieldValue().getState();
}
- assert valuesAbstractValue.isSingleFieldValue();
- ObjectState valuesState = this.valuesAbstractValue.asSingleFieldValue().getState();
- if (valuesState.isEnumValuesObjectState()) {
- return valuesState.asEnumValuesObjectState().getObjectStateForOrdinal(ordinal);
- }
+ assert fieldValue.isUnknown();
return ObjectState.empty();
}
+
+ public AbstractValue getValuesAbstractValueForPossiblyPinnedField(DexField field) {
+ assert valuesField == field || valuesAbstractValue == null;
+ return valuesAbstractValue;
+ }
}
public static class EmptyStaticValues extends StaticFieldValues {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java
index f1ec89c..2d8ddc2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java
@@ -33,6 +33,10 @@
return state[ordinal];
}
+ public int getEnumValuesSize() {
+ return state.length;
+ }
+
@Override
public boolean isEnumValuesObjectState() {
return true;
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 8de1c91..911174b 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
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -23,6 +22,7 @@
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
public abstract class SingleFieldValue extends SingleValue {
@@ -107,12 +107,9 @@
public SingleValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
AbstractValueFactory factory = appView.abstractValueFactory();
if (field.holder == field.type) {
- EnumValueInfoMap unboxedEnumInfo = appView.unboxedEnums().getEnumValueInfoMap(field.type);
- if (unboxedEnumInfo != null) {
- // Return the ordinal of the unboxed enum.
- assert unboxedEnumInfo.hasEnumValueInfo(field);
- return factory.createSingleNumberValue(
- unboxedEnumInfo.getEnumValueInfo(field).convertToInt());
+ EnumDataMap enumDataMap = appView.unboxedEnums();
+ if (enumDataMap.hasUnboxedValueFor(field)) {
+ return factory.createSingleNumberValue(enumDataMap.getUnboxedValue(field));
}
}
return factory.createSingleFieldValue(
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 00e3372..7861771 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
@@ -22,7 +22,6 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
@@ -74,6 +73,7 @@
import com.android.tools.r8.ir.optimize.ReflectionOptimizer;
import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
import com.android.tools.r8.ir.optimize.classinliner.ClassInliner;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
import com.android.tools.r8.ir.optimize.enums.EnumValueOptimizer;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoCollector;
@@ -753,7 +753,7 @@
if (enumUnboxer != null) {
enumUnboxer.unboxEnums(postMethodProcessorBuilder, executorService, feedback);
} else {
- appView.setUnboxedEnums(EnumValueInfoMapCollection.empty());
+ appView.setUnboxedEnums(EnumDataMap.empty());
}
if (!options.debug) {
new TrivialFieldAccessReprocessor(appView.withLiveness(), postMethodProcessorBuilder)
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
new file mode 100644
index 0000000..07471e7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
@@ -0,0 +1,109 @@
+// Copyright (c) 2020, 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.enums;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+
+public class EnumDataMap {
+ private final ImmutableMap<DexType, EnumData> map;
+
+ public static EnumDataMap empty() {
+ return new EnumDataMap(ImmutableMap.of());
+ }
+
+ public EnumDataMap(ImmutableMap<DexType, EnumData> map) {
+ this.map = map;
+ }
+
+ public boolean isUnboxedEnum(DexType type) {
+ return map.containsKey(type);
+ }
+
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ public Set<DexType> getUnboxedEnums() {
+ return map.keySet();
+ }
+
+ public EnumInstanceFieldKnownData getInstanceFieldData(
+ DexType enumType, DexField enumInstanceField) {
+ assert map.containsKey(enumType);
+ return map.get(enumType).getInstanceFieldData(enumInstanceField);
+ }
+
+ public boolean hasUnboxedValueFor(DexField enumStaticField) {
+ return isUnboxedEnum(enumStaticField.holder)
+ && map.get(enumStaticField.holder).hasUnboxedValueFor(enumStaticField);
+ }
+
+ public int getUnboxedValue(DexField enumStaticField) {
+ assert map.containsKey(enumStaticField.holder);
+ return map.get(enumStaticField.holder).getUnboxedValue(enumStaticField);
+ }
+
+ public int getValuesSize(DexType enumType) {
+ assert map.containsKey(enumType);
+ return map.get(enumType).getValuesSize();
+ }
+
+ public boolean matchesValuesField(DexField staticField) {
+ assert map.containsKey(staticField.holder);
+ return map.get(staticField.holder).matchesValuesField(staticField);
+ }
+
+ public static class EnumData {
+ static final int INVALID_VALUES_SIZE = -1;
+
+ // Map each enum instance field to the list of field known data.
+ final ImmutableMap<DexField, EnumInstanceFieldKnownData> instanceFieldMap;
+ // Map each enum instance (static field) to the unboxed integer value.
+ final ImmutableMap<DexField, Integer> unboxedValues;
+ // Fields matching the $VALUES content and type, usually one.
+ final ImmutableSet<DexField> valuesFields;
+ // Size of the $VALUES field, if the valuesFields set is empty, set to INVALID_VALUES_SIZE.
+ final int valuesSize;
+
+ public EnumData(
+ ImmutableMap<DexField, EnumInstanceFieldKnownData> instanceFieldMap,
+ ImmutableMap<DexField, Integer> unboxedValues,
+ ImmutableSet<DexField> valuesFields,
+ int valuesSize) {
+ this.instanceFieldMap = instanceFieldMap;
+ this.unboxedValues = unboxedValues;
+ this.valuesFields = valuesFields;
+ this.valuesSize = valuesSize;
+ }
+
+ public EnumInstanceFieldKnownData getInstanceFieldData(DexField enumInstanceField) {
+ assert instanceFieldMap.containsKey(enumInstanceField);
+ return instanceFieldMap.get(enumInstanceField);
+ }
+
+ public int getUnboxedValue(DexField field) {
+ assert unboxedValues.containsKey(field);
+ return unboxedValues.get(field);
+ }
+
+ public boolean hasUnboxedValueFor(DexField field) {
+ return unboxedValues.get(field) != null;
+ }
+
+ public boolean matchesValuesField(DexField field) {
+ return valuesFields.contains(field);
+ }
+
+ public int getValuesSize() {
+ assert valuesSize != INVALID_VALUES_SIZE;
+ return valuesSize;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldDataMap.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldDataMap.java
deleted file mode 100644
index f02e488..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldDataMap.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2020, 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.enums;
-
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
-import com.google.common.collect.ImmutableMap;
-
-public class EnumInstanceFieldDataMap {
- private final ImmutableMap<DexType, ImmutableMap<DexField, EnumInstanceFieldKnownData>>
- instanceFieldMap;
-
- public EnumInstanceFieldDataMap(
- ImmutableMap<DexType, ImmutableMap<DexField, EnumInstanceFieldKnownData>> instanceFieldMap) {
- this.instanceFieldMap = instanceFieldMap;
- }
-
- public EnumInstanceFieldKnownData getInstanceFieldData(
- DexType enumType, DexField enumInstanceField) {
- assert instanceFieldMap.containsKey(enumType);
- assert instanceFieldMap.get(enumType).containsKey(enumInstanceField);
- return instanceFieldMap.get(enumType).get(enumInstanceField);
- }
-}
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 9e95486..0d776a1 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
@@ -20,7 +20,6 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
@@ -34,6 +33,7 @@
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.EnumValuesObjectState;
import com.android.tools.r8.ir.analysis.value.ObjectState;
import com.android.tools.r8.ir.code.ArrayPut;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -53,6 +53,7 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap.EnumData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldMappingData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldOrdinalData;
@@ -71,8 +72,11 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.util.Arrays;
import java.util.Map;
+import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
@@ -91,6 +95,8 @@
private final Map<DexType, EnumStaticFieldValues> staticFieldValuesMap =
new ConcurrentHashMap<>();
+ private final DexEncodedField ordinalField;
+
private EnumUnboxingRewriter enumUnboxerRewriter;
private final boolean debugLogEnabled;
@@ -108,6 +114,13 @@
}
assert !appView.options().debug;
enumUnboxingCandidatesInfo = new EnumUnboxingCandidateAnalysis(appView, this).findCandidates();
+
+ ordinalField =
+ appView.appInfo().resolveField(factory.enumMembers.ordinalField).getResolvedField();
+ if (ordinalField == null) {
+ assert false : "Missing library field " + factory.enumMembers.ordinalField;
+ enumUnboxingCandidatesInfo.clear();
+ }
}
public static int ordinalToUnboxedInt(int ordinal) {
@@ -359,7 +372,7 @@
ExecutorService executorService,
OptimizationFeedbackDelayed feedback)
throws ExecutionException {
- EnumInstanceFieldDataMap enumInstanceFieldDataMap = finishAnalysis();
+ EnumDataMap enumDataMap = finishAnalysis();
// At this point the enum unboxing candidates are no longer candidates, they will all be
// unboxed. We extract the now immutable enums to unbox information and clear the candidate
// info.
@@ -379,13 +392,12 @@
.synthesizeEnumUnboxingUtilityClasses(
enumClassesToUnbox, enumsToUnboxWithPackageRequirement, appBuilder)
.build();
- enumUnboxerRewriter =
- new EnumUnboxingRewriter(appView, enumsToUnbox, enumInstanceFieldDataMap, relocator);
+ enumUnboxerRewriter = new EnumUnboxingRewriter(appView, enumDataMap, relocator);
NestedGraphLens enumUnboxingLens =
new EnumUnboxingTreeFixer(appView, enumsToUnbox, relocator, enumUnboxerRewriter)
.fixupTypeReferences();
enumUnboxerRewriter.setEnumUnboxingLens(enumUnboxingLens);
- appView.setUnboxedEnums(enumUnboxerRewriter.getEnumsToUnbox());
+ appView.setUnboxedEnums(enumDataMap);
GraphLens previousLens = appView.graphLens();
appView.rewriteWithLensAndApplication(enumUnboxingLens, appBuilder.build());
updateOptimizationInfos(executorService, feedback);
@@ -434,23 +446,22 @@
keepInfo.mutate(mutator -> mutator.removeKeepInfoForPrunedItems(enumsToUnbox));
}
- public EnumInstanceFieldDataMap finishAnalysis() {
+ public EnumDataMap finishAnalysis() {
analyzeInitializers();
analyzeAccessibility();
- EnumInstanceFieldDataMap enumInstanceFieldDataMap = analyzeFields();
+ EnumDataMap enumDataMap = analyzeEnumInstances();
+ assert enumDataMap.getUnboxedEnums().size() == enumUnboxingCandidatesInfo.candidates().size();
if (debugLogEnabled) {
reportEnumsAnalysis();
}
- return enumInstanceFieldDataMap;
+ return enumDataMap;
}
- private EnumInstanceFieldDataMap analyzeFields() {
- ImmutableMap.Builder<DexType, ImmutableMap<DexField, EnumInstanceFieldKnownData>> builder =
- ImmutableMap.builder();
+ private EnumDataMap analyzeEnumInstances() {
+ ImmutableMap.Builder<DexType, EnumData> builder = ImmutableMap.builder();
enumUnboxingCandidatesInfo.forEachCandidateAndRequiredInstanceFieldData(
(enumClass, fields) -> {
- ImmutableMap<DexField, EnumInstanceFieldKnownData> data =
- buildEnumInstanceFieldData(enumClass, fields);
+ EnumData data = buildData(enumClass, fields);
if (data == null) {
markEnumAsUnboxable(Reason.MISSING_INSTANCE_FIELD_DATA, enumClass);
return;
@@ -458,20 +469,136 @@
builder.put(enumClass.type, data);
});
staticFieldValuesMap.clear();
- return new EnumInstanceFieldDataMap(builder.build());
+ return new EnumDataMap(builder.build());
}
- private ImmutableMap<DexField, EnumInstanceFieldKnownData> buildEnumInstanceFieldData(
- DexProgramClass enumClass, Set<DexField> fields) {
- ImmutableMap.Builder<DexField, EnumInstanceFieldKnownData> typeBuilder = ImmutableMap.builder();
- for (DexField field : fields) {
- EnumInstanceFieldData enumInstanceFieldData = computeEnumFieldData(field, enumClass);
- if (enumInstanceFieldData.isUnknown()) {
+ private EnumData buildData(DexProgramClass enumClass, Set<DexField> fields) {
+ // This map holds all the accessible fields to their unboxed value, so we can remap the field
+ // read to the unboxed value.
+ ImmutableMap.Builder<DexField, Integer> unboxedValues = ImmutableMap.builder();
+ // This maps the ordinal to the object state, note that some fields may have been removed,
+ // hence the entry is in this map but not the enumToOrdinalMap.
+ Int2ReferenceMap<ObjectState> ordinalToObjectState = new Int2ReferenceArrayMap<>();
+ // Any fields matching the expected $VALUES content can be recorded here, they have however
+ // all the same content.
+ ImmutableSet.Builder<DexField> valuesField = ImmutableSet.builder();
+ EnumValuesObjectState valuesContents = null;
+
+ EnumStaticFieldValues enumStaticFieldValues = staticFieldValuesMap.get(enumClass.type);
+
+ // Step 1: We iterate over the field to find direct enum instance information and the values
+ // fields.
+ for (DexEncodedField staticField : enumClass.staticFields()) {
+ if (EnumUnboxingCandidateAnalysis.isEnumField(staticField, enumClass.type)) {
+ ObjectState enumState =
+ enumStaticFieldValues.getObjectStateForPossiblyPinnedField(staticField.field);
+ if (enumState != null) {
+ OptionalInt optionalOrdinal = getOrdinal(enumState);
+ if (!optionalOrdinal.isPresent()) {
+ return null;
+ }
+ int ordinal = optionalOrdinal.getAsInt();
+ unboxedValues.put(staticField.field, ordinalToUnboxedInt(ordinal));
+ ordinalToObjectState.put(ordinal, enumState);
+ }
+ } else if (EnumUnboxingCandidateAnalysis.matchesValuesField(
+ staticField, enumClass.type, factory)) {
+ AbstractValue valuesValue =
+ enumStaticFieldValues.getValuesAbstractValueForPossiblyPinnedField(staticField.field);
+ if (valuesValue == null || valuesValue.isZero()) {
+ // Unused field
+ continue;
+ }
+ if (valuesValue.isUnknown()) {
+ return null;
+ }
+ assert valuesValue.isSingleFieldValue();
+ ObjectState valuesState = valuesValue.asSingleFieldValue().getState();
+ if (!valuesState.isEnumValuesObjectState()) {
+ return null;
+ }
+ assert valuesContents == null
+ || valuesContents.equals(valuesState.asEnumValuesObjectState());
+ valuesContents = valuesState.asEnumValuesObjectState();
+ valuesField.add(staticField.field);
+ }
+ }
+
+ // Step 2: We complete the information based on the values content, since some enum instances
+ // may be reachable only though the $VALUES field.
+ if (valuesContents != null) {
+ for (int ordinal = 0; ordinal < valuesContents.getEnumValuesSize(); ordinal++) {
+ if (!ordinalToObjectState.containsKey(ordinal)) {
+ ObjectState enumState = valuesContents.getObjectStateForOrdinal(ordinal);
+ if (enumState.isEmpty()) {
+ // If $VALUES is used, we need data for all enums, at least the ordinal.
+ return null;
+ }
+ assert getOrdinal(enumState).isPresent();
+ assert getOrdinal(enumState).getAsInt() == ordinal;
+ ordinalToObjectState.put(ordinal, enumState);
+ }
+ }
+ }
+
+ // The ordinalToObjectState map may have holes at this point, if some enum instances are never
+ // used ($VALUES unused or removed, and enum instance field unused or removed), it contains
+ // only data for reachable enum instance, that is what we're interested in.
+ ImmutableMap.Builder<DexField, EnumInstanceFieldKnownData> instanceFieldBuilder =
+ ImmutableMap.builder();
+ for (DexField instanceField : fields) {
+ EnumInstanceFieldData fieldData =
+ computeEnumFieldData(instanceField, enumClass, ordinalToObjectState);
+ if (fieldData.isUnknown()) {
return null;
}
- typeBuilder.put(field, enumInstanceFieldData.asEnumFieldKnownData());
+ instanceFieldBuilder.put(instanceField, fieldData.asEnumFieldKnownData());
}
- return typeBuilder.build();
+
+ return new EnumData(
+ instanceFieldBuilder.build(),
+ unboxedValues.build(),
+ valuesField.build(),
+ valuesContents == null ? EnumData.INVALID_VALUES_SIZE : valuesContents.getEnumValuesSize());
+ }
+
+ private EnumInstanceFieldData computeEnumFieldData(
+ DexField instanceField,
+ DexProgramClass enumClass,
+ Int2ReferenceMap<ObjectState> ordinalToObjectState) {
+ DexEncodedField encodedInstanceField =
+ appView.appInfo().resolveFieldOn(enumClass, instanceField).getResolvedField();
+ assert encodedInstanceField != null;
+ boolean canBeOrdinal = instanceField.type.isIntType();
+ ImmutableInt2ReferenceSortedMap.Builder<AbstractValue> data =
+ ImmutableInt2ReferenceSortedMap.builder();
+ for (Integer ordinal : ordinalToObjectState.keySet()) {
+ ObjectState state = ordinalToObjectState.get(ordinal);
+ AbstractValue fieldValue = state.getAbstractFieldValue(encodedInstanceField);
+ if (!(fieldValue.isSingleNumberValue() || fieldValue.isSingleStringValue())) {
+ return EnumInstanceFieldUnknownData.getInstance();
+ }
+ data.put(ordinalToUnboxedInt(ordinal), fieldValue);
+ if (canBeOrdinal) {
+ assert fieldValue.isSingleNumberValue();
+ int computedValue = fieldValue.asSingleNumberValue().getIntValue();
+ if (computedValue != ordinal) {
+ canBeOrdinal = false;
+ }
+ }
+ }
+ if (canBeOrdinal) {
+ return new EnumInstanceFieldOrdinalData();
+ }
+ return new EnumInstanceFieldMappingData(data.build());
+ }
+
+ private OptionalInt getOrdinal(ObjectState state) {
+ AbstractValue field = state.getAbstractFieldValue(ordinalField);
+ if (field.isSingleNumberValue()) {
+ return OptionalInt.of(field.asSingleNumberValue().getIntValue());
+ }
+ return OptionalInt.empty();
}
private void analyzeAccessibility() {
@@ -958,49 +1085,6 @@
return Reason.OTHER_UNSUPPORTED_INSTRUCTION;
}
- private EnumInstanceFieldData computeEnumFieldData(
- DexField instanceField, DexProgramClass enumClass) {
- DexEncodedField encodedInstanceField =
- appView.appInfo().resolveFieldOn(enumClass, instanceField).getResolvedField();
- assert encodedInstanceField != null;
- boolean canBeOrdinal = instanceField.type.isIntType();
- ImmutableInt2ReferenceSortedMap.Builder<AbstractValue> data =
- ImmutableInt2ReferenceSortedMap.builder();
- EnumValueInfoMapCollection.EnumValueInfoMap enumValueInfoMap =
- appView.appInfo().getEnumValueInfoMap(enumClass.type);
- for (DexField staticField : enumValueInfoMap.enumValues()) {
- EnumStaticFieldValues enumStaticFieldValues = staticFieldValuesMap.get(enumClass.type);
- if (enumStaticFieldValues == null) {
- return EnumInstanceFieldUnknownData.getInstance();
- }
- ObjectState enumInstanceState =
- enumStaticFieldValues.getObjectStateForPossiblyPinnedEnumInstance(
- staticField, enumValueInfoMap.getEnumValueInfo(staticField).ordinal);
- if (enumInstanceState == null) {
- // The enum instance is effectively unused. No need to generate anything for it, the path
- // will never be taken.
- } else {
- AbstractValue fieldValue = enumInstanceState.getAbstractFieldValue(encodedInstanceField);
- if (!(fieldValue.isSingleNumberValue() || fieldValue.isSingleStringValue())) {
- return EnumInstanceFieldUnknownData.getInstance();
- }
- data.put(enumValueInfoMap.getEnumValueInfo(staticField).convertToInt(), fieldValue);
- if (canBeOrdinal) {
- int ordinalValue = enumValueInfoMap.getEnumValueInfo(staticField).ordinal;
- assert fieldValue.isSingleNumberValue();
- int computedValue = fieldValue.asSingleNumberValue().getIntValue();
- if (computedValue != ordinalValue) {
- canBeOrdinal = false;
- }
- }
- }
- }
- if (canBeOrdinal) {
- return new EnumInstanceFieldOrdinalData();
- }
- return new EnumInstanceFieldMappingData(data.build());
- }
-
private void reportEnumsAnalysis() {
assert debugLogEnabled;
Reporter reporter = appView.options().reporter;
@@ -1070,7 +1154,6 @@
VALUES_INVOKE,
COMPARE_TO_INVOKE,
UNSUPPORTED_LIBRARY_CALL,
- MISSING_INFO_MAP,
MISSING_INSTANCE_FIELD_DATA,
INVALID_FIELD_READ,
INVALID_FIELD_PUT,
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 b4bd339..fd9b279 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
@@ -12,7 +12,6 @@
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.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer.Reason;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
@@ -66,12 +65,6 @@
enumUnboxer.reportFailure(clazz.type, Reason.UNEXPECTED_STATIC_FIELD);
return false;
}
- EnumValueInfoMap enumValueInfoMap =
- appView.appInfo().withLiveness().getEnumValueInfoMap(clazz.type);
- if (enumValueInfoMap == null) {
- enumUnboxer.reportFailure(clazz.type, Reason.MISSING_INFO_MAP);
- return false;
- }
return true;
}
@@ -79,15 +72,9 @@
// instances.
private boolean enumHasBasicStaticFields(DexProgramClass clazz) {
for (DexEncodedField staticField : clazz.staticFields()) {
- if (staticField.field.type == clazz.type
- && staticField.accessFlags.isEnum()
- && staticField.accessFlags.isFinal()) {
+ if (isEnumField(staticField, clazz.type)) {
// Enum field, valid, do nothing.
- } else if (staticField.field.type.isArrayType()
- && staticField.field.type.toArrayElementType(factory) == clazz.type
- && staticField.accessFlags.isSynthetic()
- && staticField.accessFlags.isFinal()
- && staticField.field.name == factory.enumValuesFieldName) {
+ } else if (matchesValuesField(staticField, clazz.type, factory)) {
// Field $VALUES, valid, do nothing.
} else if (appView.appInfo().isFieldRead(staticField)) {
// Only non read static fields are valid, and they are assumed unused.
@@ -97,6 +84,21 @@
return true;
}
+ static boolean isEnumField(DexEncodedField staticField, DexType enumType) {
+ return staticField.field.type == enumType
+ && staticField.accessFlags.isEnum()
+ && staticField.accessFlags.isFinal();
+ }
+
+ static boolean matchesValuesField(
+ DexEncodedField staticField, DexType enumType, DexItemFactory factory) {
+ return staticField.field.type.isArrayType()
+ && staticField.field.type.toArrayElementType(factory) == enumType
+ && staticField.accessFlags.isSynthetic()
+ && staticField.accessFlags.isFinal()
+ && staticField.field.name == factory.enumValuesFieldName;
+ }
+
private void removeEnumsInAnnotations() {
for (DexProgramClass clazz : appView.appInfo().classes()) {
if (clazz.isAnnotation()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index c0b1831..6c20c4f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -21,9 +21,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.EnumValueInfoMapCollection;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfo;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
@@ -76,8 +73,7 @@
private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory factory;
- private final EnumValueInfoMapCollection enumsToUnbox;
- private final EnumInstanceFieldDataMap unboxedEnumsInstanceFieldData;
+ private final EnumDataMap unboxedEnumsData;
private final UnboxedEnumMemberRelocator relocator;
private NestedGraphLens enumUnboxingLens;
@@ -93,18 +89,11 @@
EnumUnboxingRewriter(
AppView<AppInfoWithLiveness> appView,
- Set<DexType> enumsToUnbox,
- EnumInstanceFieldDataMap unboxedEnumsInstanceFieldData,
+ EnumDataMap unboxedEnumsInstanceFieldData,
UnboxedEnumMemberRelocator relocator) {
this.appView = appView;
this.factory = appView.dexItemFactory();
- EnumValueInfoMapCollection.Builder builder = EnumValueInfoMapCollection.builder();
- for (DexType toUnbox : enumsToUnbox) {
- assert appView.appInfo().withLiveness().getEnumValueInfoMap(toUnbox) != null;
- builder.put(toUnbox, appView.appInfo().withLiveness().getEnumValueInfoMap(toUnbox));
- }
- this.enumsToUnbox = builder.build();
- this.unboxedEnumsInstanceFieldData = unboxedEnumsInstanceFieldData;
+ this.unboxedEnumsData = unboxedEnumsInstanceFieldData;
this.relocator = relocator;
// Custom methods for java.lang.Enum methods ordinal, equals and compareTo.
@@ -147,14 +136,10 @@
this.enumUnboxingLens = enumUnboxingLens;
}
- public EnumValueInfoMapCollection getEnumsToUnbox() {
- return enumsToUnbox;
- }
-
Set<Phi> rewriteCode(IRCode code) {
// We should not process the enum methods, they will be removed and they may contain invalid
// rewriting rules.
- if (enumsToUnbox.isEmpty()) {
+ if (unboxedEnumsData.isEmpty()) {
return Sets.newIdentityHashSet();
}
assert code.isConsistentSSABeforeTypesAreCorrect();
@@ -223,7 +208,7 @@
&& invokeStatic.getArgument(0).isConstClass()) {
DexType enumType =
invokeStatic.getArgument(0).getConstInstruction().asConstClass().getValue();
- if (enumsToUnbox.containsEnum(enumType)) {
+ if (unboxedEnumsData.isUnboxedEnum(enumType)) {
DexMethod valueOfMethod = computeValueOfUtilityMethod(enumType);
Value outValue = invokeStatic.outValue();
Value rewrittenOutValue = null;
@@ -282,17 +267,15 @@
}
if (instruction.isStaticGet()) {
StaticGet staticGet = instruction.asStaticGet();
- DexType holder = staticGet.getField().holder;
- if (enumsToUnbox.containsEnum(holder)) {
+ DexField field = staticGet.getField();
+ DexType holder = field.holder;
+ if (unboxedEnumsData.isUnboxedEnum(holder)) {
if (staticGet.outValue() == null) {
iterator.removeOrReplaceByDebugLocalRead();
continue;
}
- EnumValueInfoMap enumValueInfoMap = enumsToUnbox.getEnumValueInfoMap(holder);
- assert enumValueInfoMap != null;
affectedPhis.addAll(staticGet.outValue().uniquePhiUsers());
- EnumValueInfo enumValueInfo = enumValueInfoMap.getEnumValueInfo(staticGet.getField());
- if (enumValueInfo == null && staticGet.getField().name == factory.enumValuesFieldName) {
+ if (unboxedEnumsData.matchesValuesField(field)) {
utilityMethods.computeIfAbsent(
valuesUtilityMethod, m -> synthesizeValuesUtilityMethod());
DexField fieldValues = createValuesField(holder);
@@ -300,7 +283,9 @@
DexMethod methodValues = createValuesMethod(holder);
utilityMethods.computeIfAbsent(
methodValues,
- m -> computeValuesEncodedMethod(m, fieldValues, enumValueInfoMap.size()));
+ m ->
+ computeValuesEncodedMethod(
+ m, fieldValues, unboxedEnumsData.getValuesSize(holder)));
Value rewrittenOutValue =
code.createValue(
ArrayTypeElement.create(TypeElement.getInt(), definitelyNotNull()));
@@ -310,9 +295,10 @@
convertedEnums.put(invoke, holder);
} else {
// Replace by ordinal + 1 for null check (null is 0).
- assert enumValueInfo != null
- : "Invalid read to " + staticGet.getField().name + ", error during enum analysis";
- ConstNumber intConstant = code.createIntConstant(enumValueInfo.convertToInt());
+ assert unboxedEnumsData.hasUnboxedValueFor(field)
+ : "Invalid read to " + field.name + ", error during enum analysis";
+ ConstNumber intConstant =
+ code.createIntConstant(unboxedEnumsData.getUnboxedValue(field));
iterator.replaceCurrentInstruction(intConstant);
convertedEnums.put(intConstant, holder);
}
@@ -322,7 +308,7 @@
if (instruction.isInstanceGet()) {
InstanceGet instanceGet = instruction.asInstanceGet();
DexType holder = instanceGet.getField().holder;
- if (enumsToUnbox.containsEnum(holder)) {
+ if (unboxedEnumsData.isUnboxedEnum(holder)) {
DexMethod fieldMethod = computeInstanceFieldMethod(instanceGet.getField());
Value rewrittenOutValue =
code.createValue(
@@ -332,7 +318,7 @@
new InvokeStatic(
fieldMethod, rewrittenOutValue, ImmutableList.of(instanceGet.object()));
iterator.replaceCurrentInstruction(invoke);
- if (enumsToUnbox.containsEnum(instanceGet.getField().type)) {
+ if (unboxedEnumsData.isUnboxedEnum(instanceGet.getField().type)) {
convertedEnums.put(invoke, instanceGet.getField().type);
}
}
@@ -393,7 +379,7 @@
private DexMethod computeInstanceFieldMethod(DexField field) {
EnumInstanceFieldKnownData enumFieldKnownData =
- unboxedEnumsInstanceFieldData.getInstanceFieldData(field.holder, field);
+ unboxedEnumsData.getInstanceFieldData(field.holder, field);
if (enumFieldKnownData.isOrdinal()) {
utilityMethods.computeIfAbsent(ordinalUtilityMethod, m -> synthesizeOrdinalMethod());
return ordinalUtilityMethod;
@@ -437,7 +423,7 @@
return null;
}
DexType enumType = type.asClassType().getClassType();
- return enumsToUnbox.containsEnum(enumType) ? enumType : null;
+ return unboxedEnumsData.isUnboxedEnum(enumType) ? enumType : null;
}
public String compatibleName(DexType type) {
@@ -478,7 +464,7 @@
}
private DexMethod computeInstanceFieldUtilityMethod(DexType enumType, DexField field) {
- assert enumsToUnbox.containsEnum(enumType);
+ assert unboxedEnumsData.isUnboxedEnum(enumType);
assert field.holder == enumType || field.holder == factory.enumType;
String methodName =
"get"
@@ -498,7 +484,7 @@
private DexMethod computeStringValueOfUtilityMethod(DexType enumType) {
// TODO(b/167994636): remove duplication between instance field name read and this method.
- assert enumsToUnbox.containsEnum(enumType);
+ assert unboxedEnumsData.isUnboxedEnum(enumType);
String methodName = "string$valueOf$" + compatibleName(enumType);
DexMethod fieldMethod =
factory.createMethod(
@@ -514,7 +500,7 @@
}
private DexMethod computeValueOfUtilityMethod(DexType enumType) {
- assert enumsToUnbox.containsEnum(enumType);
+ assert unboxedEnumsData.isUnboxedEnum(enumType);
DexMethod valueOf =
factory.createMethod(
relocator.getNewMemberLocationFor(enumType),
@@ -538,7 +524,7 @@
return null;
}
DexType classType = baseType.asClassType().getClassType();
- return enumsToUnbox.containsEnum(classType) ? classType : null;
+ return unboxedEnumsData.isUnboxedEnum(classType) ? classType : null;
}
void synthesizeEnumUnboxingUtilityMethods(IRConverter converter, ExecutorService executorService)
@@ -593,15 +579,13 @@
private DexEncodedMethod synthesizeInstanceFieldMethod(
DexMethod method, DexType enumType, DexField field, AbstractValue nullValue) {
assert method.proto.returnType == field.type;
- assert unboxedEnumsInstanceFieldData.getInstanceFieldData(enumType, field).isMapping();
+ assert unboxedEnumsData.getInstanceFieldData(enumType, field).isMapping();
CfCode cfCode =
new EnumUnboxingCfCodeProvider.EnumUnboxingInstanceFieldCfCodeProvider(
appView,
method.holder,
field.type,
- unboxedEnumsInstanceFieldData
- .getInstanceFieldData(enumType, field)
- .asEnumFieldMappingData(),
+ unboxedEnumsData.getInstanceFieldData(enumType, field).asEnumFieldMappingData(),
nullValue)
.generateCfCode();
return synthesizeUtilityMethod(cfCode, method, false);
@@ -609,7 +593,7 @@
private DexEncodedMethod synthesizeValueOfUtilityMethod(DexMethod method, DexType enumType) {
assert method.proto.returnType == factory.intType;
- assert unboxedEnumsInstanceFieldData
+ assert unboxedEnumsData
.getInstanceFieldData(enumType, factory.enumMembers.nameField)
.isMapping();
CfCode cfCode =
@@ -617,7 +601,7 @@
appView,
method.holder,
enumType,
- unboxedEnumsInstanceFieldData
+ unboxedEnumsData
.getInstanceFieldData(enumType, factory.enumMembers.nameField)
.asEnumFieldMappingData())
.generateCfCode();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
index 7e78f27..262671f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
@@ -5,10 +5,10 @@
package com.android.tools.r8.ir.optimize.info.field;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Objects;
@@ -49,14 +49,14 @@
@Override
public InstanceFieldInitializationInfo rewrittenWithLens(
AppView<AppInfoWithLiveness> appView, GraphLens lens) {
- EnumValueInfoMapCollection unboxedEnums = appView.unboxedEnums();
+ EnumDataMap enumDataMap = appView.unboxedEnums();
if (dynamicLowerBoundType != null
- && unboxedEnums.containsEnum(dynamicLowerBoundType.getClassType())) {
+ && enumDataMap.isUnboxedEnum(dynamicLowerBoundType.getClassType())) {
// No point in tracking the type of primitives.
return UnknownInstanceFieldInitializationInfo.getInstance();
}
if (dynamicUpperBoundType.isClassType()
- && unboxedEnums.containsEnum(dynamicUpperBoundType.asClassType().getClassType())) {
+ && enumDataMap.isUnboxedEnum(dynamicUpperBoundType.asClassType().getClassType())) {
// No point in tracking the type of primitives.
return UnknownInstanceFieldInitializationInfo.getInstance();
}
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 f8b6d10..4fc8f54 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -26,7 +26,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.EnumValueInfoMapCollection;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
@@ -696,16 +695,6 @@
return missingTypes;
}
- public EnumValueInfoMapCollection getEnumValueInfoMapCollection() {
- assert checkIfObsolete();
- return enumValueInfoMaps;
- }
-
- public EnumValueInfoMap getEnumValueInfoMap(DexType enumType) {
- assert checkIfObsolete();
- return enumValueInfoMaps.getEnumValueInfoMap(enumType);
- }
-
public Int2ReferenceMap<DexField> getSwitchMap(DexField field) {
assert checkIfObsolete();
return switchMaps.get(field);
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 99a561f..f03ed26 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -39,7 +39,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.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.graph.classmerging.StaticallyMergedClasses;
@@ -50,6 +49,7 @@
import com.android.tools.r8.ir.conversion.MethodProcessingId;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.optimize.Inliner;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
@@ -1382,7 +1382,7 @@
public BiConsumer<DexItemFactory, StaticallyMergedClasses> staticallyMergedClassesConsumer =
ConsumerUtils.emptyBiConsumer();
- public BiConsumer<DexItemFactory, EnumValueInfoMapCollection> unboxedEnumsConsumer =
+ public BiConsumer<DexItemFactory, EnumDataMap> unboxedEnumsConsumer =
ConsumerUtils.emptyBiConsumer();
public BiConsumer<DexItemFactory, VerticallyMergedClasses> verticallyMergedClassesConsumer =
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
index 92b0b54..926a7b0 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
@@ -54,8 +54,7 @@
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), TestClass.class)
- // TODO(b/160939354): Should succeed with 42.
- .assertSuccessWithOutputLines(enableEnumUnboxing ? "0" : "42");
+ .assertSuccessWithOutputLines("42");
}
private void addProgramClasses(TestBuilder<?, ?> builder) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
index 8e5495e..2d41c1f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
@@ -8,21 +8,20 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
public class EnumUnboxingInspector {
private final DexItemFactory dexItemFactory;
- private final EnumValueInfoMapCollection unboxedEnums;
+ private final EnumDataMap unboxedEnums;
- public EnumUnboxingInspector(
- DexItemFactory dexItemFactory, EnumValueInfoMapCollection unboxedEnums) {
+ public EnumUnboxingInspector(DexItemFactory dexItemFactory, EnumDataMap unboxedEnums) {
this.dexItemFactory = dexItemFactory;
this.unboxedEnums = unboxedEnums;
}
public EnumUnboxingInspector assertUnboxed(Class<? extends Enum<?>> clazz) {
- assertTrue(unboxedEnums.containsEnum(toDexType(clazz, dexItemFactory)));
+ assertTrue(unboxedEnums.isUnboxedEnum(toDexType(clazz, dexItemFactory)));
return this;
}