Add an empty enum unboxer to avoid null checks
Change-Id: I38ef60ef3219d5cc02707a0deb2326569885af0c
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
index bd42e7d..33829cd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
/**
@@ -33,7 +34,7 @@
* code to type check until lens code rewriting, which replaces the {@link NewUnboxedEnumInstance}
* instructions by {@link ConstNumber} instructions.
*
- * <p>Note: The {@link NewUnboxedEnumInstance} is only used from {@link EnumUnboxerImpl#unboxEnums}
+ * <p>Note: The {@link NewUnboxedEnumInstance} is only used from {@link EnumUnboxer#unboxEnums}
* until the execution of the {@link com.android.tools.r8.ir.conversion.PostMethodProcessor}. There
* should be no instances of {@link NewUnboxedEnumInstance} (nor {@link CfNewUnboxedEnum}, {@link
* DexNewUnboxedEnumInstance}) after IR processing has finished.
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 83aa86a..a165209 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
@@ -78,8 +78,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.EnumUnboxerImpl;
+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;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
@@ -153,7 +152,7 @@
private final TypeChecker typeChecker;
private final ServiceLoaderRewriter serviceLoaderRewriter;
private final EnumValueOptimizer enumValueOptimizer;
- private final EnumUnboxerImpl enumUnboxer;
+ private final EnumUnboxer enumUnboxer;
public final AssumeInserter assumeInserter;
private final DynamicTypeOptimization dynamicTypeOptimization;
@@ -239,7 +238,7 @@
this.serviceLoaderRewriter = null;
this.methodOptimizationInfoCollector = null;
this.enumValueOptimizer = null;
- this.enumUnboxer = null;
+ this.enumUnboxer = EnumUnboxer.empty();
this.assumeInserter = null;
return;
}
@@ -267,8 +266,7 @@
options.enableTreeShakingOfLibraryMethodOverrides
? new LibraryMethodOverrideAnalysis(appViewWithLiveness)
: null;
- this.enumUnboxer =
- options.enableEnumUnboxing ? new EnumUnboxerImpl(appViewWithLiveness) : null;
+ this.enumUnboxer = EnumUnboxer.create(appViewWithLiveness);
this.lensCodeRewriter = new LensCodeRewriter(appViewWithLiveness, enumUnboxer);
this.inliner = new Inliner(appViewWithLiveness, lensCodeRewriter);
this.outliner = Outliner.create(appViewWithLiveness);
@@ -307,7 +305,7 @@
this.serviceLoaderRewriter = null;
this.methodOptimizationInfoCollector = null;
this.enumValueOptimizer = null;
- this.enumUnboxer = null;
+ this.enumUnboxer = EnumUnboxer.empty();
}
this.stringSwitchRemover =
options.isStringSwitchConversionEnabled()
@@ -641,10 +639,7 @@
optimization.abandonCallSitePropagationForPinnedMethodsAndOverrides(
executorService, timing);
});
- ConsumerUtils.acceptIfNotNull(
- enumUnboxer,
- enumUnboxer ->
- enumUnboxer.initializeEnumUnboxingCandidates(graphLensForPrimaryOptimizationPass));
+ enumUnboxer.prepareForPrimaryOptimizationPass(graphLensForPrimaryOptimizationPass);
ConsumerUtils.acceptIfNotNull(
classStaticizer,
classStaticizer ->
@@ -725,12 +720,8 @@
.run(executorService, feedback, timing);
}
- if (enumUnboxer != null) {
- outliner.rewriteWithLens();
- enumUnboxer.unboxEnums(this, postMethodProcessorBuilder, executorService, feedback);
- } else {
- appView.setUnboxedEnums(EnumDataMap.empty());
- }
+ outliner.rewriteWithLens();
+ enumUnboxer.unboxEnums(appView, this, postMethodProcessorBuilder, executorService, feedback);
GraphLens graphLensForSecondaryOptimizationPass = appView.graphLens();
@@ -758,9 +749,7 @@
}
timing.end();
- if (enumUnboxer != null) {
- enumUnboxer.unsetRewriter();
- }
+ enumUnboxer.unsetRewriter();
// All the code that should be impacted by the lenses inserted between phase 1 and phase 2
// have now been processed and rewritten, we clear code lens rewriting so that the class
@@ -849,9 +838,7 @@
if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
appView.protoShrinker().protoEnumSwitchMapRemover.updateVisibleStaticFieldValues();
}
- if (enumUnboxer != null) {
- enumUnboxer.updateEnumUnboxingCandidatesInfo();
- }
+ enumUnboxer.updateEnumUnboxingCandidatesInfo();
assert delayedOptimizationFeedback.noUpdatesLeft();
onWaveDoneActions.forEach(com.android.tools.r8.utils.Action::execute);
onWaveDoneActions = null;
@@ -1549,7 +1536,7 @@
appView.withArgumentPropagator(
argumentPropagator -> argumentPropagator.scan(method, code, methodProcessor, timing));
- if (enumUnboxer != null && methodProcessor.isPrimaryMethodProcessor()) {
+ if (methodProcessor.isPrimaryMethodProcessor()) {
enumUnboxer.analyzeEnums(code, conversionOptions);
}
@@ -1594,9 +1581,7 @@
appView, code, classInitializerDefaultsResult, feedback, timing);
}
}
- if (enumUnboxer != null) {
- enumUnboxer.recordEnumState(method.getHolder(), staticFieldValues);
- }
+ enumUnboxer.recordEnumState(method.getHolder(), staticFieldValues);
if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
appView
.protoShrinker()
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 10ea8e3..0356381 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -93,7 +93,7 @@
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
+import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.optimize.MemberRebindingAnalysis;
import com.android.tools.r8.utils.InternalOptions;
@@ -110,12 +110,11 @@
public class LensCodeRewriter {
private final AppView<? extends AppInfoWithClassHierarchy> appView;
- private final EnumUnboxerImpl enumUnboxer;
+ private final EnumUnboxer enumUnboxer;
private final LensCodeRewriterUtils helper;
private final InternalOptions options;
- LensCodeRewriter(
- AppView<? extends AppInfoWithClassHierarchy> appView, EnumUnboxerImpl enumUnboxer) {
+ LensCodeRewriter(AppView<? extends AppInfoWithClassHierarchy> appView, EnumUnboxer enumUnboxer) {
this.appView = appView;
this.enumUnboxer = enumUnboxer;
this.helper = new LensCodeRewriterUtils(appView);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
new file mode 100644
index 0000000..2fb3b5a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
@@ -0,0 +1,73 @@
+// 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.enums;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+public class EmptyEnumUnboxer extends EnumUnboxer {
+
+ private static final EmptyEnumUnboxer INSTANCE = new EmptyEnumUnboxer();
+
+ private EmptyEnumUnboxer() {}
+
+ static EmptyEnumUnboxer get() {
+ return INSTANCE;
+ }
+
+ @Override
+ public void prepareForPrimaryOptimizationPass(GraphLens graphLensForPrimaryOptimizationPass) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void recordEnumState(DexProgramClass clazz, StaticFieldValues staticFieldValues) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public Set<Phi> rewriteCode(IRCode code, MethodProcessor methodProcessor) {
+ // Intentionally empty.
+ return Collections.emptySet();
+ }
+
+ @Override
+ public void unboxEnums(
+ AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
+ Builder postMethodProcessorBuilder,
+ ExecutorService executorService,
+ OptimizationFeedbackDelayed feedback) {
+ appView.setUnboxedEnums(EnumDataMap.empty());
+ }
+
+ @Override
+ public void unsetRewriter() {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void updateEnumUnboxingCandidatesInfo() {
+ // Intentionally empty.
+ }
+}
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
new file mode 100644
index 0000000..2cdf22f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -0,0 +1,53 @@
+// 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.enums;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public abstract class EnumUnboxer {
+
+ public static EnumUnboxer create(AppView<AppInfoWithLiveness> appView) {
+ return appView.options().enableEnumUnboxing ? new EnumUnboxerImpl(appView) : empty();
+ }
+
+ public static EmptyEnumUnboxer empty() {
+ return EmptyEnumUnboxer.get();
+ }
+
+ public abstract void prepareForPrimaryOptimizationPass(
+ GraphLens graphLensForPrimaryOptimizationPass);
+
+ public abstract void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions);
+
+ public abstract void recordEnumState(DexProgramClass clazz, StaticFieldValues staticFieldValues);
+
+ public abstract Set<Phi> rewriteCode(IRCode code, MethodProcessor methodProcessor);
+
+ public abstract void unboxEnums(
+ AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
+ Builder postMethodProcessorBuilder,
+ ExecutorService executorService,
+ OptimizationFeedbackDelayed feedback)
+ throws ExecutionException;
+
+ public abstract void unsetRewriter();
+
+ public abstract void updateEnumUnboxingCandidatesInfo();
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index fdeea23..46eec15 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -76,7 +76,7 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.conversion.PostMethodProcessor;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
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;
@@ -131,7 +131,7 @@
import java.util.function.Function;
import java.util.function.Predicate;
-public class EnumUnboxerImpl {
+public class EnumUnboxerImpl extends EnumUnboxer {
private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory factory;
@@ -157,7 +157,7 @@
private final boolean debugLogEnabled;
private final Map<DexType, List<Reason>> debugLogs;
- public EnumUnboxerImpl(AppView<AppInfoWithLiveness> appView) {
+ EnumUnboxerImpl(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
this.factory = appView.dexItemFactory();
if (appView.options().testing.enableEnumUnboxingDebugLogs) {
@@ -180,6 +180,7 @@
return ordinalField;
}
+ @Override
public void updateEnumUnboxingCandidatesInfo() {
for (DexProgramClass candidate : candidatesToRemoveInWave) {
enumUnboxingCandidatesInfo.removeCandidate(candidate);
@@ -232,6 +233,7 @@
return enumUnboxingCandidatesInfo.getCandidateClassOrNull(type);
}
+ @Override
public void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions) {
Set<DexType> eligibleEnums = Sets.newIdentityHashSet();
for (BasicBlock block : code.blocks) {
@@ -556,7 +558,12 @@
return result;
}
- public void initializeEnumUnboxingCandidates(GraphLens graphLensForPrimaryOptimizationPass) {
+ @Override
+ public void prepareForPrimaryOptimizationPass(GraphLens graphLensForPrimaryOptimizationPass) {
+ initializeEnumUnboxingCandidates(graphLensForPrimaryOptimizationPass);
+ }
+
+ private void initializeEnumUnboxingCandidates(GraphLens graphLensForPrimaryOptimizationPass) {
assert enumUnboxingCandidatesInfo == null;
enumUnboxingCandidatesInfo =
new EnumUnboxingCandidateAnalysis(appView, this)
@@ -566,9 +573,11 @@
graphLensForPrimaryOptimizationPass);
}
+ @Override
public void unboxEnums(
+ AppView<AppInfoWithLiveness> appView,
IRConverter converter,
- PostMethodProcessor.Builder postBuilder,
+ Builder postBuilder,
ExecutorService executorService,
OptimizationFeedbackDelayed feedback)
throws ExecutionException {
@@ -871,6 +880,7 @@
return OptionalInt.empty();
}
+ @Override
public void recordEnumState(DexProgramClass clazz, StaticFieldValues staticFieldValues) {
if (staticFieldValues == null || !staticFieldValues.isEnumStaticFieldValues()) {
return;
@@ -1560,6 +1570,7 @@
return false;
}
+ @Override
public Set<Phi> rewriteCode(IRCode code, MethodProcessor methodProcessor) {
// This has no effect during primary processing since the enumUnboxerRewriter is set
// in between primary and post processing.
@@ -1569,6 +1580,7 @@
return Sets.newIdentityHashSet();
}
+ @Override
public void unsetRewriter() {
enumUnboxerRewriter = null;
}