Retain Assume instructions in LIR
Change-Id: I4a3d433c5258ba452e27a04d0b3220f90c4d506a
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index a97280f..ab49641 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -296,6 +296,9 @@
InvokeDirect constructorInvoke =
instructionIterator.nextUntil(
instruction -> {
+ if (instruction.isAssume()) {
+ return false;
+ }
// After constructor inlining we may see a load of the DEFAULT_INSTANCE field. This
// can either be read directly using a StaticGet or accessed indirectly via a
// synthetic accessor bridge (e.g., due to a -keep,allowshrinking rule).
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java
index dad9f87..415822c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java
@@ -8,11 +8,14 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.ir.code.Assume;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.AffectedValues;
+import com.android.tools.r8.utils.WorkList;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.ListIterator;
@@ -37,25 +40,47 @@
this.mapping = mapping;
}
- public void recomputeAndPropagateTypes(IRCode code, Set<Phi> affectedPhis) {
+ public Deque<Phi> unsetPhiTypes(Set<Phi> affectedPhis) {
+ if (affectedPhis.isEmpty()) {
+ return null;
+ }
+
// We have updated at least one type lattice element which can cause phi's to narrow to a more
// precise type. Because cycles in phi's can occur, we have to reset all phi's before
// computing the new values.
- Deque<Phi> worklist = new ArrayDeque<>(affectedPhis);
- while (!worklist.isEmpty()) {
- Phi phi = worklist.poll();
- phi.setType(TypeElement.getBottom());
- for (Phi affectedPhi : phi.uniquePhiUsers()) {
- if (affectedPhis.add(affectedPhi)) {
- worklist.add(affectedPhi);
+ WorkList<Assume> assumeWorklist = WorkList.newIdentityWorkList();
+ Deque<Phi> phiWorklist = new ArrayDeque<>(affectedPhis);
+ while (assumeWorklist.hasNext() || !phiWorklist.isEmpty()) {
+ assumeWorklist.process(
+ assume -> {
+ Value assumeValue = assume.outValue();
+ assumeValue.setType(TypeElement.getBottom());
+ for (Phi affectedPhi : assumeValue.uniquePhiUsers()) {
+ affectedPhis.add(affectedPhi);
+ phiWorklist.add(affectedPhi);
+ }
+ });
+ while (!phiWorklist.isEmpty()) {
+ Phi phi = phiWorklist.poll();
+ phi.setType(TypeElement.getBottom());
+ assumeWorklist.addIfNotSeen(phi.uniqueUsers(Instruction::isAssume));
+ for (Phi affectedPhi : phi.uniquePhiUsers()) {
+ if (affectedPhis.add(affectedPhi)) {
+ phiWorklist.add(affectedPhi);
+ }
}
}
}
- assert verifyAllChangedPhisAreScheduled(code, affectedPhis);
- // Assuming all values have been rewritten correctly above, the non-phi operands to phi's are
- // replaced with correct types and all other phi operands are BOTTOM.
- assert verifyAllPhiOperandsAreBottom(affectedPhis);
+ return phiWorklist;
+ }
+ public void recomputeAndPropagateTypes(IRCode code, Set<Phi> affectedPhis, Deque<Phi> worklist) {
+ if (affectedPhis.isEmpty()) {
+ assert worklist == null;
+ return;
+ }
+
+ assert verifyAllChangedPhisAreScheduled(code, affectedPhis);
AffectedValues affectedValues = new AffectedValues();
worklist.addAll(affectedPhis);
while (!worklist.isEmpty()) {
@@ -76,26 +101,6 @@
affectedValues.narrowingWithAssumeRemoval(appView, code);
}
- @SuppressWarnings("ReferenceEquality")
- private boolean verifyAllPhiOperandsAreBottom(Set<Phi> affectedPhis) {
- for (Phi phi : affectedPhis) {
- for (Value operand : phi.getOperands()) {
- if (operand.isPhi()) {
- Phi operandPhi = operand.asPhi();
- TypeElement operandType = operandPhi.getType();
- assert !affectedPhis.contains(operandPhi) || operandType.isBottom();
- assert affectedPhis.contains(operandPhi)
- || operandType.isPrimitiveType()
- || operandType.isNullType()
- || (operandType.isReferenceType()
- && operandType.fixupClassTypeReferences(appView, mapping) == operandType);
- }
- }
- }
- return true;
- }
-
- @SuppressWarnings("ReferenceEquality")
private boolean verifyAllChangedPhisAreScheduled(IRCode code, Set<Phi> affectedPhis) {
ListIterator<BasicBlock> blocks = code.listIterator();
while (blocks.hasNext()) {
@@ -103,7 +108,7 @@
for (Phi phi : block.getPhis()) {
TypeElement phiType = phi.getType();
TypeElement substituted = phiType.fixupClassTypeReferences(appView, mapping);
- assert substituted == phiType || affectedPhis.contains(phi);
+ assert substituted.equals(phiType) || affectedPhis.contains(phi);
}
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Assume.java b/src/main/java/com/android/tools/r8/ir/code/Assume.java
index 0a55c89..8c24e18 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Assume.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Assume.java
@@ -31,6 +31,10 @@
private DynamicType dynamicType;
private final Instruction origin;
+ public Assume(DynamicType dynamicType, Value dest, Value src) {
+ this(dynamicType, dest, src, null);
+ }
+
public Assume(DynamicType dynamicType, Value dest, Value src, Instruction origin) {
super(dest, src);
assert dynamicType != null;
@@ -171,7 +175,7 @@
@Override
public void buildLir(LirBuilder<Value, ?> builder) {
- throw new Unreachable(ERROR_MESSAGE);
+ builder.addAssumeNonNull(src());
}
@Override
@@ -207,8 +211,11 @@
@Override
public TypeElement evaluate(AppView<?> appView) {
if (hasNonNullAssumption()) {
- assert src().getType().isReferenceType();
- return src().getType().asReferenceType().asMeetWithNotNull();
+ if (src().getType().isReferenceType()) {
+ return src().getType().asReferenceType().asMeetWithNotNull();
+ }
+ // During IR building from LIR the src type may be bottom.
+ // During enum unboxing lens rewriting the src() may become a primitive int.
}
return src().getType();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
index 9d3a0d4..ded2f34 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
@@ -28,7 +28,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -843,7 +842,7 @@
BasicBlock invokePredecessor = invokeBlock.getPredecessors().get(0);
BasicBlock invokeSuccessor = invokeBlock.getSuccessors().get(0);
- Set<Value> argumentUsers = Sets.newIdentityHashSet();
+ AffectedValues argumentUsers = new AffectedValues();
// Map all argument values. The first one needs special handling if there is a downcast type.
List<Value> arguments = inlinee.collectArguments();
@@ -886,8 +885,7 @@
// Map the argument value that has been cast.
Value argument = arguments.get(i);
- argumentUsers.addAll(argument.affectedValues());
- argument.replaceUsers(castInstruction.outValue);
+ argument.replaceUsers(castInstruction.outValue, argumentUsers);
removeArgumentInstruction(entryBlockIterator, argument);
i++;
} else {
@@ -896,18 +894,29 @@
// Map the remaining argument values.
for (; i < invoke.inValues().size(); i++) {
- // TODO(zerny): Support inlining in --debug mode.
assert !arguments.get(i).hasLocalInfo();
Value argument = arguments.get(i);
- argumentUsers.addAll(argument.affectedValues());
- argument.replaceUsers(invoke.inValues().get(i));
+ Value callerArgument = invoke.getArgument(i);
+ // Remove redundant AssumeNonNull instructions.
+ if (callerArgument.getType().isReferenceType()
+ && callerArgument.getType().isDefinitelyNotNull()) {
+ for (Assume calleeAssume : argument.<Assume>uniqueUsers(Instruction::isAssume)) {
+ assert calleeAssume.hasNonNullAssumption();
+ assert !calleeAssume.hasDynamicTypeIgnoringNullability();
+ calleeAssume.outValue().replaceUsers(callerArgument, argumentUsers);
+ calleeAssume.remove();
+ }
+ }
+ argument.replaceUsers(callerArgument, argumentUsers);
removeArgumentInstruction(entryBlockIterator, argument);
}
assert entryBlock.getInstructions().stream().noneMatch(Instruction::isArgument);
// Actual arguments are flown to the inlinee.
- new TypeAnalysis(appView, code).narrowing(argumentUsers);
+ new TypeAnalysis(appView, inlinee)
+ .setKeepRedundantBlocksAfterAssumeRemoval(true)
+ .narrowingWithAssumeRemoval(argumentUsers);
// The inline entry is the first block now the argument instructions are gone.
BasicBlock inlineEntry = inlinee.entryBlock();
@@ -922,9 +931,9 @@
// Replace the invoke value with the return value if non-void.
assert inlineeIterator.peekNext().isReturn();
if (invoke.outValue() != null) {
- Set<Value> affectedValues = invoke.outValue().affectedValues();
+ AffectedValues affectedValues = new AffectedValues();
Return returnInstruction = inlineeIterator.peekNext().asReturn();
- invoke.outValue().replaceUsers(returnInstruction.returnValue());
+ invoke.outValue().replaceUsers(returnInstruction.returnValue(), affectedValues);
// The return type is flown to the original context.
new TypeAnalysis(appView, code)
.setKeepRedundantBlocksAfterAssumeRemoval(true)
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 23b827c..0a7b018 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
@@ -830,7 +830,7 @@
if (assumeInserter != null) {
timing.begin("Remove assume instructions");
- new AssumeRemover(appView).run(code, methodProcessor, methodProcessingContext, timing);
+ new AssumeRemover(appView, true).run(code, methodProcessor, methodProcessingContext, timing);
timing.end();
previous = printMethod(code, "IR after removing assume instructions (SSA)", previous);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeArgumentRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeArgumentRewriter.java
index 9dff1d9..e2e0ba3 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeArgumentRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeArgumentRewriter.java
@@ -51,8 +51,8 @@
DexMethod originalMethodReference,
RewrittenPrototypeDescription prototypeChanges,
Set<Phi> affectedPhis,
+ AffectedValues affectedValues,
Set<UnusedArgument> unusedArguments) {
- AffectedValues affectedValues = new AffectedValues();
ArgumentInfoCollection argumentInfoCollection = prototypeChanges.getArgumentInfoCollection();
List<Instruction> argumentPostlude = new LinkedList<>();
int oldArgumentIndex = 0;
@@ -92,7 +92,7 @@
argumentInfo.asRewrittenTypeInfo(),
affectedPhis,
newArgumentIndex);
- argument.outValue().replaceUsers(replacement.outValue());
+ argument.outValue().replaceUsers(replacement.outValue(), affectedValues);
} else if (newArgumentIndex != oldArgumentIndex) {
replacement =
Argument.builder()
@@ -136,8 +136,6 @@
instructionIterator.add(instruction);
}
}
-
- affectedValues.narrowingWithAssumeRemoval(appView, code);
}
private Argument rewriteArgumentType(
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 b293b33..c2be212 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
@@ -110,10 +110,12 @@
import com.android.tools.r8.optimize.argumentpropagation.lenscoderewriter.NullCheckInserter;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.timing.Timing;
import com.android.tools.r8.verticalclassmerging.InterfaceTypeToClassTypeLensCodeRewriterHelper;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -245,14 +247,20 @@
AffectedValues affectedValues = new AffectedValues();
Set<UnusedArgument> unusedArguments = Sets.newIdentityHashSet();
argumentRewriter.rewriteArguments(
- code, originalMethodReference, prototypeChanges, affectedPhis, unusedArguments);
+ code,
+ originalMethodReference,
+ prototypeChanges,
+ affectedPhis,
+ affectedValues,
+ unusedArguments);
if (graphLens.hasCustomLensCodeRewriter()) {
assert graphLens.getPrevious() == codeLens
|| (graphLens.getPrevious().isMemberRebindingIdentityLens()
&& graphLens.getPrevious().asMemberRebindingIdentityLens().getPrevious() == codeLens);
CustomLensCodeRewriter customLensCodeRewriter = graphLens.getCustomLensCodeRewriter();
affectedPhis.addAll(
- customLensCodeRewriter.rewriteCode(code, methodProcessor, prototypeChanges, graphLens));
+ customLensCodeRewriter.rewriteCode(
+ code, methodProcessor, prototypeChanges, affectedValues, graphLens));
}
rewritePartialDefault(
code,
@@ -317,7 +325,7 @@
Value newOutValue = makeOutValue(invokeCustom, code, graphLens, codeLens);
InvokeCustom newInvokeCustom =
new InvokeCustom(newCallSite, newOutValue, invokeCustom.inValues());
- iterator.replaceCurrentInstruction(newInvokeCustom);
+ iterator.replaceCurrentInstruction(newInvokeCustom, affectedValues);
if (newOutValue != null && newOutValue.getType() != invokeCustom.getOutType()) {
affectedPhis.addAll(newOutValue.uniquePhiUsers());
}
@@ -352,7 +360,7 @@
case INIT_CLASS:
{
InitClass initClass = current.asInitClass();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
initClass.getClassValue(),
(t, v) -> new InitClass(v, t),
@@ -390,7 +398,7 @@
if (invokedHolder.isArrayType()) {
DexArrayType arrayType = invokedHolder.asArrayType();
DexType baseType = arrayType.getBaseType();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
baseType,
(t, v) -> {
@@ -596,7 +604,7 @@
InvokeMethod.create(
actualInvokeType, actualTarget, newOutValue, newInValues, isInterface);
- iterator.replaceCurrentInstruction(newInvoke);
+ iterator.replaceCurrentInstruction(newInvoke, affectedValues);
// Insert casts for the program to type check if interfaces has been vertically
// merged into their unique (non-interface) subclass. See also b/199561570.
@@ -641,12 +649,20 @@
if (rewrittenField != field) {
newOutValue = makeOutValue(instanceGet, code, rewrittenField);
iterator.replaceCurrentInstruction(
- new InstanceGet(newOutValue, instanceGet.object(), rewrittenField));
+ new InstanceGet(newOutValue, instanceGet.object(), rewrittenField),
+ affectedValues);
}
if (newOutValue != null) {
if (lookup.hasReadCastType() && newOutValue.hasNonDebugUsers()) {
insertReadCast(
- code, blocks, iterator, instanceGet, lookup, newOutValue, affectedPhis);
+ code,
+ blocks,
+ iterator,
+ instanceGet,
+ lookup,
+ newOutValue,
+ affectedPhis,
+ affectedValues);
} else if (newOutValue.getType() != instanceGet.getOutType()) {
affectedPhis.addAll(newOutValue.uniquePhiUsers());
}
@@ -686,12 +702,20 @@
Value newOutValue = null;
if (rewrittenField != field) {
newOutValue = makeOutValue(staticGet, code, rewrittenField);
- iterator.replaceCurrentInstruction(new StaticGet(newOutValue, rewrittenField));
+ iterator.replaceCurrentInstruction(
+ new StaticGet(newOutValue, rewrittenField), affectedValues);
}
if (newOutValue != null) {
if (lookup.hasReadCastType() && newOutValue.hasNonDebugUsers()) {
insertReadCast(
- code, blocks, iterator, staticGet, lookup, newOutValue, affectedPhis);
+ code,
+ blocks,
+ iterator,
+ staticGet,
+ lookup,
+ newOutValue,
+ affectedPhis,
+ affectedValues);
} else if (newOutValue.getType() != staticGet.getOutType()) {
affectedPhis.addAll(newOutValue.uniquePhiUsers());
}
@@ -723,7 +747,7 @@
case CHECK_CAST:
{
CheckCast checkCast = current.asCheckCast();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
checkCast.getType(),
(t, v) ->
@@ -737,7 +761,7 @@
{
ConstClass constClass = current.asConstClass();
Instruction replacement =
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
constClass.getType(),
(t, v) ->
@@ -779,7 +803,7 @@
case INSTANCE_OF:
{
InstanceOf instanceOf = current.asInstanceOf();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
instanceOf.type(),
(t, v) -> new InstanceOf(v, instanceOf.value(), t),
@@ -791,7 +815,7 @@
case INVOKE_MULTI_NEW_ARRAY:
{
InvokeMultiNewArray multiNewArray = current.asInvokeMultiNewArray();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
multiNewArray.getArrayType(),
(t, v) -> new InvokeMultiNewArray(t, v, multiNewArray.inValues()),
@@ -803,7 +827,7 @@
case NEW_ARRAY_FILLED:
{
NewArrayFilled newArray = current.asNewArrayFilled();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
newArray.getArrayType(),
(t, v) -> new NewArrayFilled(t, v, newArray.inValues()),
@@ -815,7 +839,7 @@
case MOVE_EXCEPTION:
{
MoveException moveException = current.asMoveException();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
moveException.getExceptionType(),
(t, v) -> new MoveException(v, t, options),
@@ -827,7 +851,7 @@
case NEW_ARRAY_EMPTY:
{
NewArrayEmpty newArrayEmpty = current.asNewArrayEmpty();
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(
newArrayEmpty.type,
(t, v) -> new NewArrayEmpty(v, newArrayEmpty.size(), t),
@@ -839,7 +863,7 @@
case NEW_INSTANCE:
{
DexType type = current.asNewInstance().clazz;
- new InstructionReplacer(code, current, iterator, affectedPhis)
+ new InstructionReplacer(code, current, iterator, affectedPhis, affectedValues)
.replaceInstructionIfTypeChanged(type, NewInstance::new, graphLens, codeLens);
}
break;
@@ -883,7 +907,11 @@
break;
case ASSUME:
- assert false;
+ {
+ // We should only have AssumeNonNull instructions which do not require lens rewriting.
+ Assume assumeInstruction = current.asAssume();
+ assert assumeInstruction.getDynamicType().isNotNullType();
+ }
break;
default:
@@ -894,6 +922,7 @@
if (substituted != type) {
current.outValue().setType(substituted);
affectedPhis.addAll(current.outValue().uniquePhiUsers());
+ current.outValue().addAffectedValuesTo(affectedValues);
}
}
break;
@@ -901,14 +930,21 @@
}
}
if (mayHaveUnreachableBlocks) {
- code.removeUnreachableBlocks(affectedValues, affectedPhis::remove);
+ code.removeUnreachableBlocks(
+ affectedValues,
+ v -> {
+ affectedPhis.remove(v);
+ affectedValues.remove(v);
+ });
}
- affectedValues.narrowingWithAssumeRemoval(appView, code);
- if (!affectedPhis.isEmpty()) {
- new DestructivePhiTypeUpdater(appView, graphLens, codeLens)
- .recomputeAndPropagateTypes(code, affectedPhis);
- }
+ affectedValues.removeAssumeNonNullInstructionsAfterEnumUnboxing();
nullCheckInserter.processWorklist();
+ DestructivePhiTypeUpdater phiUpdater =
+ new DestructivePhiTypeUpdater(appView, graphLens, codeLens);
+ Iterables.addAll(affectedPhis, IterableUtils.filter(affectedValues, Value::isPhi));
+ Deque<Phi> phisToProcess = phiUpdater.unsetPhiTypes(affectedPhis);
+ affectedValues.propagateWithAssumeRemoval(appView, code, typeAnalysis -> {});
+ phiUpdater.recomputeAndPropagateTypes(code, affectedPhis, phisToProcess);
code.removeAllDeadAndTrivialPhis();
code.removeRedundantBlocks();
removeUnusedArguments(code, unusedArguments);
@@ -919,7 +955,6 @@
assert code.isConsistentSSABeforeTypesAreCorrect(appView);
}
-
private void insertReadCast(
IRCode code,
BasicBlockIterator blocks,
@@ -927,12 +962,13 @@
FieldGet fieldGet,
FieldLookupResult lookup,
Value newOutValue,
- Set<Phi> affectedPhis) {
+ Set<Phi> affectedPhis,
+ AffectedValues affectedValues) {
TypeElement castTypeElement =
TypeElement.fromDexType(
lookup.getReadCastType(), newOutValue.getType().nullability(), appView);
Value castOutValue = code.createValue(castTypeElement);
- newOutValue.replaceUsers(castOutValue);
+ newOutValue.replaceUsers(castOutValue, affectedValues);
CheckCast checkCast =
SafeCheckCast.builder()
.setCastType(lookup.getReadCastType())
@@ -1225,13 +1261,19 @@
private final Instruction current;
private final InstructionListIterator iterator;
private final Set<Phi> affectedPhis;
+ private final AffectedValues affectedValues;
InstructionReplacer(
- IRCode code, Instruction current, InstructionListIterator iterator, Set<Phi> affectedPhis) {
+ IRCode code,
+ Instruction current,
+ InstructionListIterator iterator,
+ Set<Phi> affectedPhis,
+ AffectedValues affectedValues) {
this.code = code;
this.current = current;
this.iterator = iterator;
this.affectedPhis = affectedPhis;
+ this.affectedValues = affectedValues;
}
@SuppressWarnings("ReferenceEquality")
@@ -1244,7 +1286,7 @@
if (newType != type) {
Value newOutValue = makeOutValue(current, code, graphLens, codeLens);
Instruction newInstruction = constructor.apply(newType, newOutValue);
- iterator.replaceCurrentInstruction(newInstruction);
+ iterator.replaceCurrentInstruction(newInstruction, affectedValues);
if (newOutValue != null) {
if (!newOutValue.getType().equals(current.getOutType())) {
affectedPhis.addAll(newOutValue.uniquePhiUsers());
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
index 4e4b0ea..05c1b36 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.ir.analysis.proto.ProtoReferences;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.passes.AdaptClassStringsRewriter;
+import com.android.tools.r8.ir.conversion.passes.AssumeRemover;
import com.android.tools.r8.ir.conversion.passes.CodeRewriterPassCollection;
import com.android.tools.r8.ir.conversion.passes.ConstResourceNumberRemover;
import com.android.tools.r8.ir.conversion.passes.ConstResourceNumberRewriter;
@@ -203,6 +204,7 @@
CodeRewriterPassCollection codeRewriterPassCollection =
CodeRewriterPassCollection.createFromNullable(
AdaptClassStringsRewriter.create(appView),
+ new AssumeRemover(appView),
new ConstResourceNumberRemover(appView),
new StoreStoreFenceToInvokeRewriter(appView),
new OriginalFieldWitnessRemover(appView),
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/AssumeRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/AssumeRemover.java
index 062558f..22492fa 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/passes/AssumeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/AssumeRemover.java
@@ -17,8 +17,15 @@
public class AssumeRemover extends CodeRewriterPass<AppInfo> {
+ private final boolean keepAssumeNonNull;
+
public AssumeRemover(AppView<?> appView) {
+ this(appView, false);
+ }
+
+ public AssumeRemover(AppView<?> appView, boolean keepAssumeNonNull) {
super(appView);
+ this.keepAssumeNonNull = keepAssumeNonNull;
}
@Override
@@ -47,6 +54,16 @@
continue;
}
+ Value src = assumeInstruction.src();
+ Value dest = assumeInstruction.outValue();
+ if (src.getType().isNullable() && assumeInstruction.hasNonNullAssumption()) {
+ if (keepAssumeNonNull) {
+ assumeInstruction.clearDynamicTypeAssumption();
+ continue;
+ }
+ valuesThatRequireWidening.addAll(dest.affectedValues());
+ }
+
// Delete the Assume instruction and replace uses of the out-value by the in-value:
// y <- Assume(x)
// ...
@@ -55,11 +72,6 @@
// becomes:
//
// x.foo()
- Value src = assumeInstruction.src();
- Value dest = assumeInstruction.outValue();
- valuesThatRequireWidening.addAll(dest.affectedValues());
-
- // Replace `dest` by `src`.
needToCheckTrivialPhis |= dest.numberOfPhiUsers() > 0;
dest.replaceUsers(src);
assumeInstruction.remove();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
index 8702d9c..d71d0f3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
@@ -43,6 +43,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryLibRewriter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryRetargeter;
import com.android.tools.r8.ir.desugar.itf.LirToLirInterfaceMethodRewriter;
+import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.optimize.CustomLensCodeRewriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -211,6 +212,7 @@
IRCode code,
MethodProcessor methodProcessor,
RewrittenPrototypeDescription prototypeChanges,
+ AffectedValues affectedValues,
NonIdentityGraphLens lens) {
boolean changed = false;
BasicBlockIterator blocks = code.listIterator();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AffectedValues.java b/src/main/java/com/android/tools/r8/ir/optimize/AffectedValues.java
index 2258b27..1f02eeb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AffectedValues.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AffectedValues.java
@@ -8,13 +8,17 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.code.Assume;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Value;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -51,6 +55,12 @@
}
}
+ public void propagate(AppView<?> appView, IRCode code) {
+ if (hasNext()) {
+ new TypeAnalysis(appView, code).propagate(this);
+ }
+ }
+
public void propagateWithAssumeRemoval(
AppView<?> appView, IRCode code, Consumer<TypeAnalysis> typeAnalysisConsumer) {
if (hasNext()) {
@@ -67,6 +77,25 @@
}
}
+ public void removeAssumeNonNullInstructionsAfterEnumUnboxing() {
+ List<Assume> assumeInstructionsToRemove = new ArrayList<>();
+ removeIf(
+ value -> {
+ if (value.isDefinedByInstructionSatisfying(Instruction::isAssume)) {
+ Assume assume = value.getDefinition().asAssume();
+ if (value.getDefinition().getFirstOperand().getType().isInt()) {
+ assumeInstructionsToRemove.add(assume);
+ return true;
+ }
+ }
+ return false;
+ });
+ for (Assume assume : assumeInstructionsToRemove) {
+ assume.outValue().replaceUsers(assume.src(), this);
+ assume.remove();
+ }
+ }
+
@Override
public boolean add(Value value) {
return affectedValues.add(value);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CustomLensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CustomLensCodeRewriter.java
index 1f046d2..73b12ee 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CustomLensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CustomLensCodeRewriter.java
@@ -15,11 +15,12 @@
public interface CustomLensCodeRewriter {
CustomLensCodeRewriter EMPTY =
- (code, methodProcessor, prototypeChanges, lens) -> Sets.newIdentityHashSet();
+ (code, methodProcessor, prototypeChanges, affectedValues, lens) -> Sets.newIdentityHashSet();
Set<Phi> rewriteCode(
IRCode code,
MethodProcessor methodProcessor,
RewrittenPrototypeDescription prototypeChanges,
+ AffectedValues affectedValues,
NonIdentityGraphLens lens);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index 849a899..ee8b6c7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -85,7 +85,8 @@
if (current.isAssumeWithNonNullAssumption()) {
Assume nonNull = current.asAssume();
Instruction origin = nonNull.origin();
- if (origin.isInvokeInterface()
+ if (origin != null
+ && origin.isInvokeInterface()
&& !origin.asInvokeInterface().getReceiver().hasLocalInfo()
&& devirtualizedCall.containsKey(origin.asInvokeInterface())
&& origin.asInvokeInterface().getReceiver() == nonNull.getAliasForOutValue()) {
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 c925743..66e1512 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
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.proto.ProtoInliningReasonStrategy;
import com.android.tools.r8.ir.analysis.type.Nullability;
+import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlockIterator;
@@ -1381,7 +1382,7 @@
return false;
}
- /** Applies member rebinding to the inlinee and inserts assume instructions. */
+ /** Applies member value propagation to the inlinee and inserts assume instructions. */
private void postProcessInlineeBlocks(
IRCode code,
BasicBlockIterator blockIterator,
@@ -1390,7 +1391,7 @@
Timing timing) {
BasicBlock state = IteratorUtils.peekNext(blockIterator);
- // Insert assume instructions in the inlinee blocks.
+ // Run member value propagation on the inlinee blocks.
Set<BasicBlock> inlineeBlocks = Sets.newIdentityHashSet();
rewindBlockIterator(
blockIterator,
@@ -1400,6 +1401,10 @@
inlineeBlocks.add(inlineeBlock);
}
});
+ applyMemberValuePropagationToInlinee(code, blockIterator, inlineeBlocks);
+
+ // Insert assume instructions in the inlinee blocks.
+ rewindBlockIterator(blockIterator, block);
insertAssumeInstructions(code, blockIterator, inlineeBlocks, timing);
// Restore the old state of the iterator.
@@ -1417,6 +1422,19 @@
assert !blockIterator.hasNext();
}
+ private void applyMemberValuePropagationToInlinee(
+ IRCode code, BasicBlockIterator blockIterator, Set<BasicBlock> inlineeBlocks) {
+ AffectedValues affectedValues = new AffectedValues();
+ new R8MemberValuePropagation(appView)
+ .run(code, blockIterator, affectedValues, inlineeBlocks::contains);
+ if (!affectedValues.isEmpty()) {
+ new TypeAnalysis(appView, code)
+ .setKeepRedundantBlocksAfterAssumeRemoval(true)
+ .narrowingWithAssumeRemoval(affectedValues);
+ }
+ assert !blockIterator.hasNext();
+ }
+
private void rewindBlockIterator(ListIterator<BasicBlock> blockIterator, BasicBlock callerBlock) {
rewindBlockIterator(blockIterator, callerBlock, ConsumerUtils.emptyConsumer());
}
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 09141b9..aca7012 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
@@ -46,6 +46,7 @@
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.optimize.CustomLensCodeRewriter;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
import com.android.tools.r8.ir.optimize.enums.classification.CheckNotNullEnumUnboxerMethodClassification;
@@ -153,6 +154,7 @@
IRCode code,
MethodProcessor methodProcessor,
RewrittenPrototypeDescription prototypeChanges,
+ AffectedValues affectedValues,
NonIdentityGraphLens graphLens) {
// We should not process the enum methods, they will be removed and they may contain invalid
// rewriting rules.
@@ -201,6 +203,7 @@
code,
eventConsumer,
affectedPhis,
+ affectedValues,
convertedEnums,
blocks,
block,
@@ -216,12 +219,14 @@
convertedEnums,
iterator,
affectedPhis,
+ affectedValues,
eventConsumer);
} else if (instruction.isStaticGet()) {
rewriteStaticGet(
code,
eventConsumer,
affectedPhis,
+ affectedValues,
convertedEnums,
seenBlocks,
instructionsToRemove,
@@ -229,7 +234,12 @@
instruction.asStaticGet());
} else if (instruction.isInstanceGet()) {
rewriteInstanceGet(
- code, eventConsumer, convertedEnums, iterator, instruction.asInstanceGet());
+ code,
+ eventConsumer,
+ affectedValues,
+ convertedEnums,
+ iterator,
+ instruction.asInstanceGet());
} else if (instruction.isArrayAccess()) {
rewriteArrayAccess(
code, affectedPhis, convertedEnums, iterator, instruction.asArrayAccess());
@@ -351,6 +361,7 @@
private void rewriteInstanceGet(
IRCode code,
EnumUnboxerMethodProcessorEventConsumer eventConsumer,
+ AffectedValues affectedValues,
Map<Instruction, DexType> convertedEnums,
InstructionListIterator iterator,
InstanceGet instanceGet) {
@@ -369,7 +380,7 @@
}
InvokeStatic invoke =
new InvokeStatic(fieldMethod.getReference(), rewrittenOutValue, ImmutableList.of(in));
- iterator.replaceCurrentInstruction(invoke);
+ iterator.replaceCurrentInstruction(invoke, affectedValues);
if (unboxedEnumsData.isUnboxedEnum(instanceGet.getField().type)) {
convertedEnums.put(invoke, instanceGet.getField().type);
}
@@ -380,6 +391,7 @@
IRCode code,
EnumUnboxerMethodProcessorEventConsumer eventConsumer,
Set<Phi> affectedPhis,
+ AffectedValues affectedValues,
Map<Instruction, DexType> convertedEnums,
Set<BasicBlock> seenBlocks,
Set<Instruction> instructionsToRemove,
@@ -409,7 +421,7 @@
.setFreshOutValue(appView, code)
.setSingleArgument(sizeValue)
.build();
- iterator.replaceCurrentInstruction(invoke);
+ iterator.replaceCurrentInstruction(invoke, affectedValues);
convertedEnums.put(invoke, holder);
@@ -417,11 +429,11 @@
// clone(). If so, remove it, since SharedUtilityClass.values(size) returns a fresh
// array. This is needed because the javac generated implementation of MyEnum.values()
// is implemented as `return $VALUES.clone()`.
- removeRedundantValuesArrayCloning(invoke, instructionsToRemove, seenBlocks);
+ removeRedundantValuesArrayCloning(invoke, affectedValues, instructionsToRemove, seenBlocks);
} else if (unboxedEnumsData.hasUnboxedValueFor(field)) {
// Replace by ordinal + 1 for null check (null is 0).
ConstNumber intConstant = code.createIntConstant(unboxedEnumsData.getUnboxedValue(field));
- iterator.replaceCurrentInstruction(intConstant);
+ iterator.replaceCurrentInstruction(intConstant, affectedValues);
convertedEnums.put(intConstant, holder);
} else {
// Nothing to do, handled by lens code rewriting.
@@ -440,6 +452,7 @@
IRCode code,
EnumUnboxerMethodProcessorEventConsumer eventConsumer,
Set<Phi> affectedPhis,
+ AffectedValues affectedValues,
Map<Instruction, DexType> convertedEnums,
BasicBlockIterator blocks,
BasicBlock block,
@@ -456,17 +469,20 @@
|| invokedMethod.match(factory.enumMembers.hashCode)) {
replaceEnumInvoke(
iterator,
+ affectedValues,
invoke,
getSharedUtilityClass().ensureOrdinalMethod(appView, context, eventConsumer));
} else if (invokedMethod.match(factory.enumMembers.equals)) {
replaceEnumInvoke(
iterator,
+ affectedValues,
invoke,
getSharedUtilityClass().ensureEqualsMethod(appView, context, eventConsumer));
} else if (invokedMethod == factory.enumMembers.compareTo
|| invokedMethod == factory.enumMembers.compareToWithObject) {
replaceEnumInvoke(
iterator,
+ affectedValues,
invoke,
getSharedUtilityClass().ensureCompareToMethod(appView, context, eventConsumer));
} else if (invokedMethod == factory.enumMembers.nameMethod) {
@@ -494,10 +510,10 @@
DexClassAndMethod dexClassAndMethod = appView.definitionFor(lookupMethod);
assert dexClassAndMethod != null;
assert dexClassAndMethod.isProgramMethod();
- replaceEnumInvoke(iterator, invoke, dexClassAndMethod.asProgramMethod());
+ replaceEnumInvoke(iterator, affectedValues, invoke, dexClassAndMethod.asProgramMethod());
}
} else if (invokedMethod == factory.objectMembers.getClass) {
- rewriteNullCheck(iterator, invoke, context, eventConsumer);
+ rewriteNullCheck(iterator, affectedValues, invoke, context, eventConsumer);
} else if (invoke.isInvokeVirtual() || invoke.isInvokeInterface()) {
DexMethod refinedDispatchMethodReference =
enumUnboxingLens.lookupRefinedDispatchMethod(
@@ -508,12 +524,13 @@
assert refinedDispatchMethod != null;
assert refinedDispatchMethod.isProgramMethod();
InvokeStatic replacement =
- replaceEnumInvoke(iterator, invoke, refinedDispatchMethod.asProgramMethod());
+ replaceEnumInvoke(
+ iterator, affectedValues, invoke, refinedDispatchMethod.asProgramMethod());
if (replacement.hasOutValue()
&& refinedDispatchMethodReference.getReturnType().isIntType()
&& !invokedMethod.getReturnType().isIntType()) {
Value rewrittenOutValue = code.createValue(TypeElement.getInt());
- replacement.outValue().replaceUsers(rewrittenOutValue);
+ replacement.outValue().replaceUsers(rewrittenOutValue, affectedValues);
replacement.setOutValue(rewrittenOutValue);
affectedPhis.addAll(rewrittenOutValue.uniquePhiUsers());
convertedEnums.put(replacement, enumType);
@@ -613,6 +630,7 @@
Map<Instruction, DexType> convertedEnums,
InstructionListIterator instructionIterator,
Set<Phi> affectedPhis,
+ AffectedValues affectedValues,
EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
ProgramMethod context = code.context();
DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
@@ -644,7 +662,7 @@
valueOfMethod.getReference(),
rewrittenOutValue,
Collections.singletonList(invoke.inValues().get(1)));
- instructionIterator.replaceCurrentInstruction(replacement);
+ instructionIterator.replaceCurrentInstruction(replacement, affectedValues);
convertedEnums.put(replacement, enumType);
}
return;
@@ -657,7 +675,7 @@
Value argument = invoke.getFirstArgument();
DexType enumType = getEnumClassTypeOrNull(argument, convertedEnums);
if (enumType != null) {
- rewriteNullCheck(instructionIterator, invoke, context, eventConsumer);
+ rewriteNullCheck(instructionIterator, affectedValues, invoke, context, eventConsumer);
}
} else if (invokedMethod == factory.objectsMethods.requireNonNullWithMessage) {
assert invoke.arguments().size() == 2;
@@ -666,6 +684,7 @@
if (enumType != null) {
replaceEnumInvoke(
instructionIterator,
+ affectedValues,
invoke,
getSharedUtilityClass()
.ensureCheckNotZeroWithMessageMethod(appView, context, eventConsumer));
@@ -690,6 +709,7 @@
}
replaceEnumInvoke(
instructionIterator,
+ affectedValues,
invoke,
getSharedUtilityClass().ensureObjectsEqualsMethod(appView, context, eventConsumer),
newArguments);
@@ -784,24 +804,29 @@
private void rewriteNullCheck(
InstructionListIterator iterator,
+ AffectedValues affectedValues,
InvokeMethod invoke,
ProgramMethod context,
EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
assert !invoke.hasOutValue() || !invoke.outValue().hasAnyUsers();
replaceEnumInvoke(
iterator,
+ affectedValues,
invoke,
getSharedUtilityClass().ensureCheckNotZeroMethod(appView, context, eventConsumer));
}
private void removeRedundantValuesArrayCloning(
- InvokeStatic invoke, Set<Instruction> instructionsToRemove, Set<BasicBlock> seenBlocks) {
+ InvokeStatic invoke,
+ AffectedValues affectedValues,
+ Set<Instruction> instructionsToRemove,
+ Set<BasicBlock> seenBlocks) {
for (Instruction user : invoke.outValue().aliasedUsers()) {
if (user.isInvokeVirtual()) {
InvokeVirtual cloneCandidate = user.asInvokeVirtual();
if (cloneCandidate.getInvokedMethod().match(appView.dexItemFactory().objectMembers.clone)) {
if (cloneCandidate.hasOutValue()) {
- cloneCandidate.outValue().replaceUsers(invoke.outValue());
+ cloneCandidate.outValue().replaceUsers(invoke.outValue(), affectedValues);
}
BasicBlock cloneBlock = cloneCandidate.getBlock();
if (cloneBlock == invoke.getBlock() || !seenBlocks.contains(cloneBlock)) {
@@ -867,12 +892,16 @@
}
private InvokeStatic replaceEnumInvoke(
- InstructionListIterator iterator, InvokeMethod invoke, ProgramMethod method) {
- return replaceEnumInvoke(iterator, invoke, method, invoke.arguments());
+ InstructionListIterator iterator,
+ AffectedValues affectedValues,
+ InvokeMethod invoke,
+ ProgramMethod method) {
+ return replaceEnumInvoke(iterator, affectedValues, invoke, method, invoke.arguments());
}
private InvokeStatic replaceEnumInvoke(
InstructionListIterator iterator,
+ AffectedValues affectedValues,
InvokeMethod invoke,
ProgramMethod method,
List<Value> arguments) {
@@ -883,7 +912,7 @@
arguments);
assert !replacement.hasOutValue()
|| !replacement.getInvokedMethod().getReturnType().isVoidType();
- iterator.replaceCurrentInstruction(replacement);
+ iterator.replaceCurrentInstruction(replacement, affectedValues);
return replacement;
}
@@ -900,9 +929,10 @@
}
private DexType getEnumClassTypeOrNull(Value receiver, Map<Instruction, DexType> convertedEnums) {
- TypeElement type = receiver.getType();
+ Value receiverRoot = receiver.getAliasedValue();
+ TypeElement type = receiverRoot.getType();
if (type.isInt()) {
- return receiver.isPhi() ? null : convertedEnums.get(receiver.getDefinition());
+ return receiverRoot.isPhi() ? null : convertedEnums.get(receiverRoot.getDefinition());
}
return getEnumClassTypeOrNull(type);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
index 5c37f51..25d60f4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.RetracerForCodePrinting;
@@ -90,15 +91,17 @@
.build());
// Remove any assume instructions linked to the argument and replace all returns by return-void.
+ AffectedValues affectedValues = new AffectedValues();
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
if (instruction.isAssume()) {
- instruction.outValue().replaceUsers(instruction.getFirstOperand());
+ instruction.outValue().replaceUsers(instruction.getFirstOperand(), affectedValues);
instructionIterator.removeOrReplaceByDebugLocalRead();
} else if (instruction.isReturn() && instruction.asReturn().hasReturnValue()) {
instructionIterator.replaceCurrentInstruction(new Return());
}
}
+ affectedValues.propagate(appView, code);
// Transfer the IR to the given checkNotZero() method.
return new IRCode(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/numberunboxer/NumberUnboxerRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/numberunboxer/NumberUnboxerRewriter.java
index 5e26100..8423e1c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/numberunboxer/NumberUnboxerRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/numberunboxer/NumberUnboxerRewriter.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.optimize.CustomLensCodeRewriter;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.ImmutableList;
@@ -43,6 +44,7 @@
IRCode code,
MethodProcessor methodProcessor,
RewrittenPrototypeDescription prototypeChanges,
+ AffectedValues affectedValues,
NonIdentityGraphLens graphLens) {
assert graphLens.isNumberUnboxerLens();
Set<Phi> affectedPhis = Sets.newIdentityHashSet();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
index d82c653..9644ff7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
@@ -49,6 +49,7 @@
import com.android.tools.r8.ir.code.Mul;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.OutlineCallerPosition;
import com.android.tools.r8.ir.code.Position.OutlineCallerPosition.OutlineCallerPositionBuilder;
@@ -64,7 +65,6 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.ir.conversion.passes.AssumeRemover;
import com.android.tools.r8.ir.conversion.passes.MoveResultRewriter;
import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
@@ -1280,17 +1280,25 @@
}
// Prepare to remove the instruction.
- List<Value> inValues = orderedInValues(current, returnValue);
- for (Value value : inValues) {
- value.removeUser(current);
- int argumentIndex = outline.argumentMap.get(argumentsMapIndex++);
- if (argumentIndex >= in.size()) {
- assert argumentIndex == in.size();
- in.add(value);
+ if (current.isAssume()) {
+ Value src = current.getFirstOperand();
+ current.outValue().replaceUsers(src, affectedValues);
+ src.removeUser(current);
+ src.uniquePhiUsers().forEach(Phi::removeTrivialPhi);
+ current.clearOutValue();
+ } else {
+ List<Value> inValues = orderedInValues(current, returnValue);
+ for (Value value : inValues) {
+ value.removeUser(current);
+ int argumentIndex = outline.argumentMap.get(argumentsMapIndex++);
+ if (argumentIndex >= in.size()) {
+ assert argumentIndex == in.size();
+ in.add(value);
+ }
}
- }
- if (current.outValue() != null) {
- returnValue = current.outValue();
+ if (!outline.returnType.isVoidType() && current.hasOutValue()) {
+ returnValue = current.outValue();
+ }
}
// The invoke of the outline method will be placed at the last instruction index,
// so don't mark that for removal.
@@ -1302,9 +1310,6 @@
}
assert lastInstruction != null;
assert outlineMethod.proto.createShortyString().length() - 1 == in.size();
- if (returnValue != null && !returnValue.isUsed()) {
- returnValue = null;
- }
Invoke outlineInvoke = new InvokeStatic(outlineMethod, returnValue, in);
lastInstruction.getBlock();
outlineInvoke.setPosition(
@@ -1453,7 +1458,6 @@
// unused out-values.
new MoveResultRewriter(appView).run(code, Timing.empty());
converter.deadCodeRemover.run(code, Timing.empty());
- new AssumeRemover(appView).run(code, Timing.empty());
consumer.accept(code);
},
appView.options().getThreadingModule(),
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/bottomup/OutlineMarkerRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/bottomup/OutlineMarkerRewriter.java
index 38ecd97..956e2a8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/bottomup/OutlineMarkerRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/bottomup/OutlineMarkerRewriter.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.conversion.LensCodeArgumentRewriter;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.passes.DexConstantOptimizer;
+import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.optimize.ConstantCanonicalizer;
import com.android.tools.r8.ir.optimize.DeadCodeRemover;
import com.android.tools.r8.lightir.Lir2IRConverter;
@@ -101,10 +102,17 @@
}
Set<Phi> affectedPhis = Collections.emptySet();
+ AffectedValues affectedValues = new AffectedValues();
Set<UnusedArgument> unusedArguments = Collections.emptySet();
new LensCodeArgumentRewriter(appView)
.rewriteArguments(
- code, method.getReference(), outline.getProtoChanges(), affectedPhis, unusedArguments);
+ code,
+ method.getReference(),
+ outline.getProtoChanges(),
+ affectedPhis,
+ affectedValues,
+ unusedArguments);
+ affectedValues.narrowingWithAssumeRemoval(appView, code);
// Run shorten live ranges to push materialized constants to their uses.
ConstantCanonicalizer constantCanonicalizer = new ConstantCanonicalizer(appView, method, code);
diff --git a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
index ed38c17..e2e5997 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
+import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -32,6 +33,7 @@
import com.android.tools.r8.ir.code.ArrayGet;
import com.android.tools.r8.ir.code.ArrayLength;
import com.android.tools.r8.ir.code.ArrayPut;
+import com.android.tools.r8.ir.code.Assume;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.CheckCast;
@@ -107,6 +109,7 @@
import com.android.tools.r8.ir.code.Xor;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.optimize.outliner.bottomup.Outline;
import com.android.tools.r8.lightir.LirBuilder.IntSwitchPayload;
import com.android.tools.r8.lightir.LirBuilder.StringSwitchPayload;
@@ -153,6 +156,32 @@
IRCode irCode = parser.getIRCode(method, conversionOptions);
// Some instructions have bottom types (e.g., phis). Compute their actual types by widening.
new TypeAnalysis(appView, irCode).widening();
+
+ // Remove redundant Assume instructions for non-null phis. This may be needed since during
+ // type narrowing we don't unset the type of phis. When rebuilding the phi types as part of IR
+ // building we may get more precise type information for phis.
+ List<Value> assumeValuesToRemove = new ArrayList<>();
+ for (Assume assume : irCode.<Assume>instructions(Instruction::isAssume)) {
+ TypeElement operandType = assume.src().getType();
+ if (operandType.isDefinitelyNotNull()) {
+ assumeValuesToRemove.add(assume.outValue());
+ }
+ }
+ if (!assumeValuesToRemove.isEmpty()) {
+ new TypeAnalysis(appView, irCode).narrowingWithAssumeRemoval(assumeValuesToRemove);
+ }
+
+ // Remove Assume instructions for where the operand is definitely null.
+ AffectedValues affectedValues = new AffectedValues();
+ for (Assume assume : irCode.<Assume>instructions(Instruction::isAssume)) {
+ if (assume.getFirstOperand().getType().isNullType()) {
+ assume.outValue().replaceUsers(assume.src(), affectedValues);
+ assume.src().uniquePhiUsers().forEach(Phi::removeTrivialPhi);
+ assume.remove();
+ }
+ }
+ affectedValues.propagate(appView, irCode);
+
return irCode;
}
@@ -889,6 +918,13 @@
}
@Override
+ public void onAssumeNonNull(EV value) {
+ Value src = getValue(value);
+ Value dest = getOutValueForNextInstruction(TypeElement.getBottom());
+ addInstruction(new Assume(DynamicType.definitelyNotNull(), dest, src));
+ }
+
+ @Override
public void onCheckCast(DexType type, EV value, boolean ignoreCompatRules) {
Value dest = getOutValueForNextInstruction(type.toTypeElement(appView, Nullability.bottom()));
addInstruction(new CheckCast(dest, getValue(value), type, ignoreCompatRules));
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index e974f3c..35306bc 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -689,6 +689,10 @@
return addOneValueInstruction(LirOpcodes.ARRAYLENGTH, array);
}
+ public LirBuilder<V, EV> addAssumeNonNull(V value) {
+ return addOneValueInstruction(LirOpcodes.ASSUMENONNULL, value);
+ }
+
public LirBuilder<V, EV> addCheckCast(DexType type, V value, boolean ignoreCompatRules) {
int opcode = ignoreCompatRules ? LirOpcodes.CHECKCAST_IGNORE_COMPAT : LirOpcodes.CHECKCAST;
return addInstructionTemplate(
diff --git a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
index a278bca..af1c08e 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
@@ -217,6 +217,7 @@
int STORESTOREFENCE = 230;
int OUTLINEMARKER = 231;
int STRINGCONCAT = 232;
+ int ASSUMENONNULL = 233;
static String toString(int opcode) {
switch (opcode) {
@@ -499,7 +500,9 @@
case IFNONNULL:
return "IFNONNULL";
- // Non-CF instructions.
+ // Non-CF instructions.
+ case ASSUMENONNULL:
+ return "ASSUMENONNULL";
case ICONST:
return "ICONST";
case LCONST:
diff --git a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
index 8e48282..ea6bbc5 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -487,6 +487,10 @@
onInstruction();
}
+ public void onAssumeNonNull(EV value) {
+ onInstruction();
+ }
+
public void onCheckCast(DexType type, EV value, boolean ignoreCompatRules) {
onInstruction();
}
@@ -1221,6 +1225,11 @@
onArrayLength(getNextValueOperand(view));
return;
}
+ case LirOpcodes.ASSUMENONNULL:
+ {
+ onAssumeNonNull(getNextValueOperand(view));
+ return;
+ }
case LirOpcodes.CHECKCAST:
{
DexType type = getNextDexTypeOperand(view);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
index b70b0b2..70db827 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.NumberConversionType;
import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.ir.optimize.outliner.bottomup.Outline;
import com.android.tools.r8.lightir.LirBuilder.IntSwitchPayload;
import com.android.tools.r8.lightir.LirBuilder.StringSwitchPayload;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
@@ -227,6 +228,11 @@
}
@Override
+ public void onOutlineMarker(Outline outline, List<EV> arguments) {
+ appendValueArguments(arguments);
+ }
+
+ @Override
public void onIf(IfType ifKind, int blockIndex, EV valueIndex) {
appendValueArguments(valueIndex);
builder.append(fmtInsnIndex(blockIndex));
@@ -380,6 +386,11 @@
}
@Override
+ public void onAssumeNonNull(EV value) {
+ appendOutValue().append(fmtValueIndex(value));
+ }
+
+ @Override
public void onCheckCast(DexType type, EV value, boolean ignoreCompatRules) {
appendOutValue();
appendValueArguments(value);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java b/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java
index e8e6db9..1c2b87f 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java
@@ -285,6 +285,8 @@
return DexNewArray.SIZE;
case ARRAYLENGTH:
return DexArrayLength.SIZE;
+ case ASSUMENONNULL:
+ return 0;
case ATHROW:
return DexThrow.SIZE;
case CHECKCAST:
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 7596e39..1984ac5 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
@@ -717,6 +717,13 @@
return staticType;
}
+ if (!newStaticFieldType.toTypeElement(appView).strictlyLessThan(staticFieldType, appView)) {
+ // Can happen when the dynamic type is an intersection type with >1 interfaces. In this case
+ // the conversion to DexType resorts to the class type, which may be less precise than the
+ // current static field type.
+ return staticType;
+ }
+
if (!AccessUtils.isAccessibleInSameContextsAs(newStaticFieldType, staticType, appView)) {
return staticType;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
index 15e33f5..fc69f73 100644
--- a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
+++ b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
@@ -27,7 +27,6 @@
import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
import com.android.tools.r8.ir.conversion.OneTimeMethodProcessor;
import com.android.tools.r8.ir.conversion.callgraph.CallSiteInformation;
-import com.android.tools.r8.ir.conversion.passes.AssumeRemover;
import com.android.tools.r8.ir.optimize.DefaultInliningOracle;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.inliner.InliningIRProvider;
@@ -147,8 +146,6 @@
IRCode code = method.buildIR(appView, MethodConversionOptions.forLirPhase(appView));
inliner.performInlining(
method, code, getSimpleFeedback(), methodProcessor, Timing.empty());
- new AssumeRemover(appView)
- .run(code, methodProcessor, methodProcessingContext, Timing.empty());
LirCode<Integer> lirCode =
new IRToLirFinalizer(appView)
.finalizeCode(code, BytecodeMetadataProvider.empty(), Timing.empty());
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracingImpl.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracingImpl.java
index 759878b..648a3e7 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracingImpl.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracingImpl.java
@@ -29,7 +29,6 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.IRFinalizer;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
-import com.android.tools.r8.ir.conversion.passes.AssumeRemover;
import com.android.tools.r8.ir.conversion.passes.ThrowCatchOptimizer;
import com.android.tools.r8.ir.optimize.AssumeInserter;
import com.android.tools.r8.ir.optimize.info.OptimizationInfoRemover;
@@ -377,7 +376,6 @@
// Run dead code elimination.
new ThrowCatchOptimizer(appView).run(ir, Timing.empty());
rewriter.getDeadCodeRemover().run(ir, Timing.empty());
- new AssumeRemover(appView).run(ir, Timing.empty());
// Finalize out of IR.
IRFinalizer<?> finalizer =
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index be552b1..55d3f2e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -261,7 +261,7 @@
assertThat(
inspector.clazz(
"class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateless$1"),
- isPresent());
+ isAbsent());
assertThat(
inspector.clazz(
"class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateful$1"),
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index 9f6cede..3a61e7b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -75,7 +75,7 @@
long paramNullCheckCount =
countCall(testMethod, "Intrinsics", "checkParameterIsNotNull");
// One after Iterator#hasNext, and another in the filter predicate: sinceYear != null.
- assertEquals(testParameters.isCfRuntime() ? 5 : 2, ifzCount);
+ assertEquals(2, ifzCount);
assertEquals(0, paramNullCheckCount);
});
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
index e22c378..c59b6dc 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
@@ -108,37 +108,8 @@
SyntheticItemsTestUtils syntheticItems) {
if (parameters.isCfRuntime()) {
if (kotlinParameters.getLambdaGeneration().isClass()) {
- inspector
- .assertIsCompleteMergeGroup(
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$4"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$5"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$6"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$7"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$8"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testFirst$9"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$4"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$5"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$6"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$7"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$8"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testSecond$9"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testThird$1"),
- lambdasInInput.getKStyleLambdaReferenceFromTypeName(
- getTestName(), "MainKt$testThird$2"))
- .assertNoOtherClassesMerged();
+ assertEquals(1, inspector.getMergeGroups().size());
+ assertEquals(19, inspector.getSources().size());
} else {
inspector.assertNoClassesMerged();
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
index 48b85e2..4b0a02a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
@@ -138,10 +138,7 @@
}
}
assertEquals(
- kotlinParameters.getLambdaGeneration().isInvokeDynamic()
- ? 0
- : parameters.isDexRuntime() ? 1 : 0,
- lambdasInOutput.size());
+ kotlinParameters.getLambdaGeneration().isInvokeDynamic() ? 0 : 1, lambdasInOutput.size());
}
private String getExpectedOutput() {
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java
index e6f3ee5..1514010 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java
@@ -19,8 +19,7 @@
// With horizontal class merging enabled the method body for debug is cleared, because the
// forwarded call to the class specific implementation has no side effects. The call to the
// function from main persists.
- private static final String EXPECTED_OUTPUT = StringUtils.lines("[Base] message2", "The end");
- private static final String EXPECTED_OUTPUT_DEX =
+ private static final String EXPECTED_OUTPUT =
StringUtils.lines("[Base] message1", "[Base] message2", "The end");
enum TestConfig {
@@ -45,16 +44,6 @@
throw new Unreachable();
}
}
-
- public String expectedOutput(TestParameters parameters) {
- switch (this) {
- case SPECIFIC_RULES:
- case NON_SPECIFIC_RULES_WITH_EXTENDS:
- return parameters.isCfRuntime() ? EXPECTED_OUTPUT : EXPECTED_OUTPUT_DEX;
- default:
- throw new Unreachable();
- }
- }
}
private final TestParameters parameters;
@@ -81,7 +70,7 @@
.addDontObfuscate()
.setMinApi(parameters)
.run(parameters.getRuntime(), MAIN)
- .assertSuccessWithOutput(config.expectedOutput(parameters));
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
}
static class BaseClass {