Introduce a 'top' element for the class inliner analysis
Bug: 181746071
Change-Id: Ia62a189777d6bd0c8a03c8f1cb29f1575f2473d0
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/AnalysisContext.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/AnalysisContext.java
index 8c05bf0..5f63f4c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/AnalysisContext.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/AnalysisContext.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
/**
- * The context used for the {@link AnalysisState} lattice.
+ * The context used for the {@link ParameterUsages} lattice.
*
* <p>By only using {@link DefaultAnalysisContext} a context-insensitive result is achieved.
* Context-sensitive results can be achieved by forking different analysis contexts during the class
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsages.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsages.java
new file mode 100644
index 0000000..84bae0e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsages.java
@@ -0,0 +1,50 @@
+// 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.classinliner.analysis;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+
+public class BottomParameterUsages extends ParameterUsages {
+
+ private static final BottomParameterUsages INSTANCE = new BottomParameterUsages();
+
+ private BottomParameterUsages() {}
+
+ static BottomParameterUsages getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ ParameterUsages externalize() {
+ return this;
+ }
+
+ @Override
+ public ParameterUsagePerContext get(int parameter) {
+ return ParameterUsagePerContext.bottom();
+ }
+
+ @Override
+ public boolean isBottom() {
+ return true;
+ }
+
+ @Override
+ ParameterUsages put(int parameter, ParameterUsagePerContext usagePerContext) {
+ Int2ObjectOpenHashMap<ParameterUsagePerContext> backing = new Int2ObjectOpenHashMap<>();
+ backing.put(parameter, usagePerContext);
+ return NonEmptyParameterUsages.create(backing);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == INSTANCE;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java
index fee1048..677518c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ClassInlinerMethodConstraintAnalysis.java
@@ -17,20 +17,30 @@
public static ClassInlinerMethodConstraint analyze(
AppView<AppInfoWithLiveness> appView, ProgramMethod method, IRCode code) {
- if (method.getDefinition().isClassInitializer()) {
+ if (method.getDefinition().isClassInitializer()
+ || method.getDefinition().getNumberOfArguments() == 0) {
return ClassInlinerMethodConstraint.alwaysFalse();
}
// Analyze code.
- IntraproceduralDataflowAnalysis<AnalysisState> analysis =
+ IntraproceduralDataflowAnalysis<ParameterUsages> analysis =
new IntraproceduralDataflowAnalysis<>(
- AnalysisState.bottom(), new TransferFunction(appView, method));
- SuccessfulDataflowAnalysisResult<AnalysisState> result =
+ ParameterUsages.bottom(), new TransferFunction(appView, method));
+ SuccessfulDataflowAnalysisResult<ParameterUsages> result =
analysis.run(code.entryBlock()).asSuccessfulAnalysisResult();
if (result == null) {
return ClassInlinerMethodConstraint.alwaysFalse();
}
- return new ConditionalClassInlinerMethodConstraint(result.join().externalize());
+ // TODO(b/181746071): This always returns a non-empty result, that should be transformed into
+ // bottom or top.
+ ParameterUsages usages = result.join();
+ if (usages.isBottom()) {
+ return ClassInlinerMethodConstraint.alwaysTrue();
+ }
+ if (usages.isTop()) {
+ return ClassInlinerMethodConstraint.alwaysFalse();
+ }
+ return new ConditionalClassInlinerMethodConstraint(usages.externalize());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/AnalysisState.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsages.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/AnalysisState.java
rename to src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsages.java
index a09ada2..2fb4a19 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/AnalysisState.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsages.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
-import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractState;
import com.android.tools.r8.ir.code.AssumeAndCheckCastAliasedValueConfiguration;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.ArrayUtils;
@@ -12,7 +11,6 @@
import com.android.tools.r8.utils.IntObjConsumer;
import com.android.tools.r8.utils.IntObjToObjFunction;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.ArrayList;
import java.util.Collection;
@@ -63,43 +61,34 @@
* <p>Finally, to provide the information for each method parameter, this class provides a mapping
* from parameters to {@link ParameterUsagePerContext}.
*/
-public class AnalysisState extends AbstractState<AnalysisState> {
+public class NonEmptyParameterUsages extends ParameterUsages {
- private static final AnalysisState BOTTOM = new AnalysisState();
private static final AssumeAndCheckCastAliasedValueConfiguration aliasedValueConfiguration =
AssumeAndCheckCastAliasedValueConfiguration.getInstance();
private final Int2ObjectMap<ParameterUsagePerContext> backing;
- private AnalysisState() {
- this.backing = Int2ObjectMaps.emptyMap();
- }
-
- private AnalysisState(Int2ObjectMap<ParameterUsagePerContext> backing) {
+ private NonEmptyParameterUsages(Int2ObjectMap<ParameterUsagePerContext> backing) {
assert !backing.isEmpty() : "Should use bottom() instead";
this.backing = backing;
}
- static AnalysisState bottom() {
- return BOTTOM;
+ public static ParameterUsages create(Int2ObjectMap<ParameterUsagePerContext> backing) {
+ return backing.isEmpty() ? bottom() : new NonEmptyParameterUsages(backing);
}
- public static AnalysisState create(Int2ObjectMap<ParameterUsagePerContext> backing) {
- return backing.isEmpty() ? bottom() : new AnalysisState(backing);
+ @Override
+ public NonEmptyParameterUsages asNonEmpty() {
+ return this;
}
- /**
- * Converts instances of {@link InternalNonEmptyParameterUsage} to {@link NonEmptyParameterUsage}.
- *
- * <p>This is needed because {@link InternalNonEmptyParameterUsage} is not suitable for being
- * stored in {@link com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo}, since it
- * contains references to IR instructions.
- */
- AnalysisState externalize() {
+ @Override
+ NonEmptyParameterUsages externalize() {
return rebuildParameters((parameter, usagePerContext) -> usagePerContext.externalize());
}
- AnalysisState put(int parameter, ParameterUsagePerContext parameterUsagePerContext) {
+ @Override
+ ParameterUsages put(int parameter, ParameterUsagePerContext parameterUsagePerContext) {
Int2ObjectOpenHashMap<ParameterUsagePerContext> newBacking =
new Int2ObjectOpenHashMap<>(backing);
newBacking.put(parameter, parameterUsagePerContext);
@@ -110,22 +99,18 @@
Int2ObjectMapUtils.forEach(backing, consumer);
}
+ @Override
public ParameterUsagePerContext get(int parameter) {
assert backing.containsKey(parameter);
ParameterUsagePerContext value = backing.get(parameter);
return value != null ? value : ParameterUsagePerContext.bottom();
}
- public boolean isBottom() {
- assert !backing.isEmpty() || this == bottom();
- return backing.isEmpty();
- }
-
- AnalysisState abandonClassInliningInCurrentContexts(Value value) {
+ NonEmptyParameterUsages abandonClassInliningInCurrentContexts(Value value) {
return rebuildParameter(value, (context, usage) -> ParameterUsage.top());
}
- AnalysisState abandonClassInliningInCurrentContexts(Collection<Value> values) {
+ NonEmptyParameterUsages abandonClassInliningInCurrentContexts(Collection<Value> values) {
if (values.isEmpty()) {
return this;
}
@@ -141,7 +126,7 @@
: usagePerContext);
}
- AnalysisState abandonClassInliningInCurrentContexts(
+ NonEmptyParameterUsages abandonClassInliningInCurrentContexts(
Iterable<Value> values, Predicate<Value> predicate) {
List<Value> filtered = new ArrayList<>();
for (Value value : values) {
@@ -153,7 +138,7 @@
return abandonClassInliningInCurrentContexts(filtered);
}
- AnalysisState rebuildParameter(
+ NonEmptyParameterUsages rebuildParameter(
Value value, BiFunction<AnalysisContext, ParameterUsage, ParameterUsage> transformation) {
Value valueRoot = value.getAliasedValue(aliasedValueConfiguration);
assert valueRoot.isArgument();
@@ -165,7 +150,7 @@
: usagePerContext);
}
- AnalysisState rebuildParameters(
+ NonEmptyParameterUsages rebuildParameters(
IntObjToObjFunction<ParameterUsagePerContext, ParameterUsagePerContext> transformation) {
Int2ObjectMap<ParameterUsagePerContext> rebuiltBacking = null;
for (Int2ObjectMap.Entry<ParameterUsagePerContext> entry : backing.int2ObjectEntrySet()) {
@@ -190,16 +175,10 @@
rebuiltBacking.put(parameter, newUsagePerContext);
}
}
- return rebuiltBacking != null ? create(rebuiltBacking) : this;
+ return rebuiltBacking != null ? new NonEmptyParameterUsages(rebuiltBacking) : this;
}
- @Override
- public AnalysisState asAbstractState() {
- return this;
- }
-
- @Override
- public AnalysisState join(AnalysisState otherAnalysisState) {
+ public NonEmptyParameterUsages join(NonEmptyParameterUsages otherAnalysisState) {
if (isBottom()) {
return otherAnalysisState;
}
@@ -214,7 +193,7 @@
parameterUsagePerContext.join(
Int2ObjectMapUtils.getOrDefault(
newBacking, parameter, ParameterUsagePerContext.bottom()))));
- return AnalysisState.create(newBacking);
+ return new NonEmptyParameterUsages(newBacking);
}
@Override
@@ -222,7 +201,7 @@
if (other == null || getClass() != other.getClass()) {
return false;
}
- AnalysisState analysisState = (AnalysisState) other;
+ NonEmptyParameterUsages analysisState = (NonEmptyParameterUsages) other;
return backing.equals(analysisState.backing);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java
index 4c5c2c2..e2ad8da 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java
@@ -80,7 +80,7 @@
abstract ParameterUsage setParameterUsedAsLock();
- static BottomParameterUsage bottom() {
+ public static BottomParameterUsage bottom() {
return BottomParameterUsage.getInstance();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsages.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsages.java
new file mode 100644
index 0000000..6b4cffb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsages.java
@@ -0,0 +1,65 @@
+// 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.classinliner.analysis;
+
+import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractState;
+
+public abstract class ParameterUsages extends AbstractState<ParameterUsages> {
+
+ @Override
+ public ParameterUsages asAbstractState() {
+ return this;
+ }
+
+ public NonEmptyParameterUsages asNonEmpty() {
+ return null;
+ }
+
+ /**
+ * This converts instances inside this {@link ParameterUsages} instance that are not suitable for
+ * being stored in optimization info into instances that can be stored in the optimization info.
+ *
+ * <p>For example, converts instances of {@link InternalNonEmptyParameterUsage} to {@link
+ * NonEmptyParameterUsage}. This is needed because {@link InternalNonEmptyParameterUsage} is not
+ * suitable for being stored in {@link
+ * com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo}, since it contains references to
+ * IR instructions.
+ */
+ abstract ParameterUsages externalize();
+
+ public abstract ParameterUsagePerContext get(int parameter);
+
+ public boolean isBottom() {
+ return false;
+ }
+
+ public boolean isTop() {
+ return false;
+ }
+
+ @Override
+ public ParameterUsages join(ParameterUsages state) {
+ if (isBottom()) {
+ return state;
+ }
+ if (state.isBottom()) {
+ return this;
+ }
+ if (isTop() || state.isTop()) {
+ return top();
+ }
+ return asNonEmpty().join(state.asNonEmpty());
+ }
+
+ abstract ParameterUsages put(int parameter, ParameterUsagePerContext usagePerContext);
+
+ public static BottomParameterUsages bottom() {
+ return BottomParameterUsages.getInstance();
+ }
+
+ public static UnknownParameterUsages top() {
+ return UnknownParameterUsages.getInstance();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
index c501bbe..740a8cd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractTransferFunction;
-import com.android.tools.r8.ir.analysis.framework.intraprocedural.TransferFunctionResult;
import com.android.tools.r8.ir.code.AliasedValueConfiguration;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.Assume;
@@ -45,7 +44,7 @@
import com.google.common.collect.Sets;
import java.util.Set;
-class TransferFunction implements AbstractTransferFunction<AnalysisState> {
+class TransferFunction implements AbstractTransferFunction<ParameterUsages> {
private static final AliasedValueConfiguration aliasedValueConfiguration =
AssumeAndCheckCastAliasedValueConfiguration.getInstance();
@@ -73,7 +72,7 @@
}
@Override
- public TransferFunctionResult<AnalysisState> apply(Instruction instruction, AnalysisState state) {
+ public ParameterUsages apply(Instruction instruction, ParameterUsages state) {
if (instruction.isArgument()) {
return analyzeArgument(instruction.asArgument(), state);
}
@@ -82,6 +81,12 @@
// purpose of class inlining we can ignore this instruction.
return state;
}
+ assert !state.isBottom();
+ assert !state.isTop();
+ return apply(instruction, state.asNonEmpty());
+ }
+
+ private ParameterUsages apply(Instruction instruction, NonEmptyParameterUsages state) {
switch (instruction.opcode()) {
case ASSUME:
return analyzeAssume(instruction.asAssume(), state);
@@ -111,8 +116,8 @@
}
@Override
- public AnalysisState computeBlockEntryState(
- BasicBlock block, BasicBlock predecessor, AnalysisState predecessorExitState) {
+ public ParameterUsages computeBlockEntryState(
+ BasicBlock block, BasicBlock predecessor, ParameterUsages predecessorExitState) {
// TODO(b/173337498): Fork a new `FIELD=x` analysis context for the successor block if the
// predecessor ends with an if or switch instruction, and the successor block is the
// `FIELD=x` target of the predecessor. To avoid an excessive number of contexts being
@@ -121,8 +126,7 @@
return predecessorExitState;
}
- private TransferFunctionResult<AnalysisState> analyzeArgument(
- Argument argument, AnalysisState state) {
+ private ParameterUsages analyzeArgument(Argument argument, ParameterUsages state) {
// Only consider arguments that could store an instance eligible for class inlining. Note that
// we can't ignore parameters with a library type, since instances of program classes could
// still flow into such parameters.
@@ -138,18 +142,17 @@
return state.put(argument.getIndex(), NonEmptyParameterUsagePerContext.createInitial());
}
- private TransferFunctionResult<AnalysisState> analyzeAssume(Assume assume, AnalysisState state) {
+ private ParameterUsages analyzeAssume(Assume assume, NonEmptyParameterUsages state) {
// Mark the value as ineligible for class inlining if it has phi users.
return assume.outValue().hasPhiUsers() ? fail(assume, state) : state;
}
- private TransferFunctionResult<AnalysisState> analyzeCheckCast(
- CheckCast checkCast, AnalysisState state) {
+ private ParameterUsages analyzeCheckCast(CheckCast checkCast, NonEmptyParameterUsages state) {
// Mark the value as ineligible for class inlining if it has phi users.
return checkCast.outValue().hasPhiUsers() ? fail(checkCast, state) : state;
}
- private TransferFunctionResult<AnalysisState> analyzeIf(If theIf, AnalysisState state) {
+ private ParameterUsages analyzeIf(If theIf, NonEmptyParameterUsages state) {
// Null/not-null tests are ok.
if (theIf.isZeroTest()) {
assert argumentsOfInterest.contains(theIf.lhs().getAliasedValue(aliasedValueConfiguration));
@@ -160,8 +163,8 @@
return fail(theIf, state);
}
- private TransferFunctionResult<AnalysisState> analyzeInstanceGet(
- InstanceGet instanceGet, AnalysisState state) {
+ private ParameterUsages analyzeInstanceGet(
+ InstanceGet instanceGet, NonEmptyParameterUsages state) {
// Instance field reads are OK, as long as the field resolves, since the class inliner will
// just replace the field read by the value of the field.
FieldResolutionResult resolutionResult = appView.appInfo().resolveField(instanceGet.getField());
@@ -176,8 +179,8 @@
return fail(instanceGet, state);
}
- private TransferFunctionResult<AnalysisState> analyzeInstancePut(
- InstancePut instancePut, AnalysisState state) {
+ private ParameterUsages analyzeInstancePut(
+ InstancePut instancePut, NonEmptyParameterUsages state) {
// Instance field writes are OK, as long as the field resolves and the receiver is not being
// assigned (in that case the receiver escapes, and thus it is not eligible for class
// inlining).
@@ -199,8 +202,7 @@
}
}
- private TransferFunctionResult<AnalysisState> analyzeInvokeDirect(
- InvokeDirect invoke, AnalysisState state) {
+ private ParameterUsages analyzeInvokeDirect(InvokeDirect invoke, NonEmptyParameterUsages state) {
// We generally don't class inline instances that escape through invoke-direct calls, but we
// make an exception for forwarding/parent constructor calls that does not leak the receiver.
state =
@@ -242,8 +244,8 @@
return state;
}
- private TransferFunctionResult<AnalysisState> analyzeInvokeInterface(
- InvokeInterface invoke, AnalysisState state) {
+ private ParameterUsages analyzeInvokeInterface(
+ InvokeInterface invoke, NonEmptyParameterUsages state) {
// We only allow invoke-interface instructions where the parameter is in the receiver position.
state =
state.abandonClassInliningInCurrentContexts(
@@ -264,8 +266,7 @@
receiverRoot, (context, usage) -> usage.addMethodCallWithParameterAsReceiver(invoke));
}
- private TransferFunctionResult<AnalysisState> analyzeInvokeStatic(
- InvokeStatic invoke, AnalysisState state) {
+ private ParameterUsages analyzeInvokeStatic(InvokeStatic invoke, NonEmptyParameterUsages state) {
// We generally don't class inline instances that escape through invoke-static calls, but we
// make an exception for calls to Objects.requireNonNull().
SingleResolutionResult resolutionResult =
@@ -282,8 +283,8 @@
return fail(invoke, state);
}
- private TransferFunctionResult<AnalysisState> analyzeInvokeVirtual(
- InvokeVirtual invoke, AnalysisState state) {
+ private ParameterUsages analyzeInvokeVirtual(
+ InvokeVirtual invoke, NonEmptyParameterUsages state) {
// We only allow invoke-virtual instructions where the parameter is in the receiver position.
state =
state.abandonClassInliningInCurrentContexts(
@@ -304,21 +305,19 @@
receiverRoot, (context, usage) -> usage.addMethodCallWithParameterAsReceiver(invoke));
}
- private TransferFunctionResult<AnalysisState> analyzeMonitor(
- Monitor monitor, AnalysisState state) {
+ private ParameterUsages analyzeMonitor(Monitor monitor, NonEmptyParameterUsages state) {
// Record that the receiver is used as a lock in each context that may reach this monitor
// instruction.
return state.rebuildParameter(
monitor.object(), (context, usage) -> usage.setParameterUsedAsLock());
}
- private TransferFunctionResult<AnalysisState> analyzeReturn(
- Return theReturn, AnalysisState state) {
+ private ParameterUsages analyzeReturn(Return theReturn, NonEmptyParameterUsages state) {
return state.rebuildParameter(
theReturn.returnValue(), (context, usage) -> usage.setParameterReturned());
}
- private TransferFunctionResult<AnalysisState> fail(Instruction instruction, AnalysisState state) {
+ private ParameterUsages fail(Instruction instruction, NonEmptyParameterUsages state) {
return state.abandonClassInliningInCurrentContexts(
instruction.inValues(), this::isArgumentOfInterest);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsages.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsages.java
new file mode 100644
index 0000000..13e32a7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsages.java
@@ -0,0 +1,46 @@
+// 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.classinliner.analysis;
+
+public class UnknownParameterUsages extends ParameterUsages {
+
+ private static final UnknownParameterUsages INSTANCE = new UnknownParameterUsages();
+
+ private UnknownParameterUsages() {}
+
+ static UnknownParameterUsages getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ ParameterUsages externalize() {
+ return this;
+ }
+
+ @Override
+ public ParameterUsagePerContext get(int parameter) {
+ return ParameterUsagePerContext.top();
+ }
+
+ @Override
+ public boolean isTop() {
+ return true;
+ }
+
+ @Override
+ ParameterUsages put(int parameter, ParameterUsagePerContext usagePerContext) {
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == INSTANCE;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
new file mode 100644
index 0000000..30ae12b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
@@ -0,0 +1,40 @@
+// 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.classinliner.constraint;
+
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
+
+public class AlwaysTrueClassInlinerMethodConstraint implements ClassInlinerMethodConstraint {
+
+ private static final AlwaysTrueClassInlinerMethodConstraint INSTANCE =
+ new AlwaysTrueClassInlinerMethodConstraint();
+
+ private AlwaysTrueClassInlinerMethodConstraint() {}
+
+ static AlwaysTrueClassInlinerMethodConstraint getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
+ return this;
+ }
+
+ @Override
+ public ParameterUsage getParameterUsage(int parameter) {
+ return ParameterUsage.bottom();
+ }
+
+ @Override
+ public boolean isEligibleForNewInstanceClassInlining(ProgramMethod method, int parameter) {
+ return true;
+ }
+
+ @Override
+ public boolean isEligibleForStaticGetClassInlining(ProgramMethod method, int parameter) {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
index c86f373..9b04087 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
@@ -20,4 +20,8 @@
static AlwaysFalseClassInlinerMethodConstraint alwaysFalse() {
return AlwaysFalseClassInlinerMethodConstraint.getInstance();
}
+
+ static AlwaysTrueClassInlinerMethodConstraint alwaysTrue() {
+ return AlwaysTrueClassInlinerMethodConstraint.getInstance();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
index 5c384e8..be9d99a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
@@ -6,35 +6,38 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.classinliner.analysis.AnalysisContext;
-import com.android.tools.r8.ir.optimize.classinliner.analysis.AnalysisState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.NonEmptyParameterUsage;
+import com.android.tools.r8.ir.optimize.classinliner.analysis.NonEmptyParameterUsages;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsagePerContext;
+import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsages;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class ConditionalClassInlinerMethodConstraint implements ClassInlinerMethodConstraint {
- private final AnalysisState usages;
+ private final ParameterUsages usages;
- public ConditionalClassInlinerMethodConstraint(AnalysisState usages) {
+ public ConditionalClassInlinerMethodConstraint(ParameterUsages usages) {
+ assert !usages.isTop();
this.usages = usages;
}
@Override
public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
- // TODO(b/181746071): Introduce a 'TOP' variant to reduce memory usage and add check here.
if (usages.isBottom()) {
return this;
}
Int2ObjectMap<ParameterUsagePerContext> backing = new Int2ObjectOpenHashMap<>();
- usages.forEach(
- (parameter, usagePerContext) -> {
- if (parameter > 0) {
- backing.put(parameter - 1, usagePerContext);
- }
- });
- return new ConditionalClassInlinerMethodConstraint(AnalysisState.create(backing));
+ usages
+ .asNonEmpty()
+ .forEach(
+ (parameter, usagePerContext) -> {
+ if (parameter > 0) {
+ backing.put(parameter - 1, usagePerContext);
+ }
+ });
+ return new ConditionalClassInlinerMethodConstraint(NonEmptyParameterUsages.create(backing));
}
@Override