Version 1.5.49 Cherry pick: Add regression test for b/134304597 CL: https://r8-review.googlesource.com/c/r8/+/39304 Cherry pick: Don't inline methods that returns an integer as a boolean on dalvik. CL: https://r8-review.googlesource.com/c/r8/+/39642 Bug: 134304597 Change-Id: I6bacef2006c86c3f2467981e0ed247776bc35a2d
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java index b714708..20ca7f5 100644 --- a/src/main/java/com/android/tools/r8/Version.java +++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@ // This field is accessed from release scripts using simple pattern matching. // Therefore, changing this field could break our release scripts. - public static final String LABEL = "1.5.48"; + public static final String LABEL = "1.5.49"; private Version() { }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java index 90c112c..f72aef7 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
@@ -57,7 +57,7 @@ return nesting; } - TypeLatticeElement getArrayMemberTypeAsMemberType() { + public TypeLatticeElement getArrayMemberTypeAsMemberType() { return memberTypeLattice; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java index e12d780..ab3268b 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
@@ -17,7 +17,7 @@ public abstract class TypeLatticeElement { public static final BottomTypeLatticeElement BOTTOM = BottomTypeLatticeElement.getInstance(); public static final TopTypeLatticeElement TOP = TopTypeLatticeElement.getInstance(); - static final BooleanTypeLatticeElement BOOLEAN = BooleanTypeLatticeElement.getInstance(); + public static final BooleanTypeLatticeElement BOOLEAN = BooleanTypeLatticeElement.getInstance(); static final ByteTypeLatticeElement BYTE = ByteTypeLatticeElement.getInstance(); static final ShortTypeLatticeElement SHORT = ShortTypeLatticeElement.getInstance(); static final CharTypeLatticeElement CHAR = CharTypeLatticeElement.getInstance();
diff --git a/src/main/java/com/android/tools/r8/ir/code/And.java b/src/main/java/com/android/tools/r8/ir/code/And.java index cc782ff..357edf8 100644 --- a/src/main/java/com/android/tools/r8/ir/code/And.java +++ b/src/main/java/com/android/tools/r8/ir/code/And.java
@@ -11,6 +11,7 @@ import com.android.tools.r8.code.AndIntLit8; import com.android.tools.r8.code.AndLong; import com.android.tools.r8.code.AndLong2Addr; +import java.util.Set; public class And extends LogicalBinop { @@ -87,4 +88,9 @@ CfLogicalBinop.Opcode getCfOpcode() { return CfLogicalBinop.Opcode.And; } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return leftValue().knownToBeBoolean(seen) && rightValue().knownToBeBoolean(seen); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java index b8f4e9f..54004cb 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Argument.java +++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -14,14 +14,18 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import java.util.Set; /** * Argument pseudo instruction used to introduce values for all arguments for SSA conversion. */ public class Argument extends Instruction { - public Argument(Value outValue) { + private final boolean knownToBeBoolean; + + public Argument(Value outValue, boolean knownToBeBoolean) { super(outValue); + this.knownToBeBoolean = knownToBeBoolean; outValue.markAsArgument(); } @@ -99,4 +103,9 @@ public boolean hasInvariantOutType() { return true; } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return knownToBeBoolean; + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java index e082dcd..5690a16 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java +++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -28,6 +28,7 @@ import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.ir.regalloc.RegisterAllocator; import java.util.Arrays; +import java.util.Set; public class ArrayGet extends Instruction implements ImpreciseMemberTypeInstruction { @@ -248,6 +249,13 @@ } @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return array().getTypeLattice().isArrayType() + && array().getTypeLattice().asArrayTypeLatticeElement().getArrayMemberTypeAsMemberType() + == TypeLatticeElement.BOOLEAN; + } + + @Override public void constrainType(TypeConstraintResolver constraintResolver) { constraintResolver.constrainArrayMemberType(type, dest(), array(), t -> type = t); }
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 dc8a32b..bac4a5a 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
@@ -15,6 +15,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import java.util.Set; public class Assume<An extends Assumption> extends Instruction { @@ -67,6 +68,11 @@ } @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return src().knownToBeBoolean(seen); + } + + @Override public String getInstructionName() { if (isAssumeDynamicType()) { return "AssumeDynamicType";
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java index b9bc91b..e831599 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -26,6 +26,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.utils.InternalOutputMode; import com.android.tools.r8.utils.NumberUtils; +import java.util.Set; import java.util.function.Function; public class ConstNumber extends ConstInstruction { @@ -314,4 +315,8 @@ return true; } + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return this.value == 0 || this.value == 1; + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java index 3fc9562..6a59713 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java +++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -29,6 +29,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import java.util.Set; import org.objectweb.asm.Opcodes; public class InstanceGet extends FieldInstruction { @@ -38,6 +39,11 @@ } @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return getField().type.isBooleanType(); + } + + @Override public <T> T accept(InstructionVisitor<T> visitor) { return visitor.visit(this); }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java index 600c299..c74ab1b 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java +++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -14,6 +14,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import java.util.Set; public class InstanceOf extends Instruction { @@ -104,4 +105,9 @@ public void buildCf(CfBuilder builder) { builder.add(new CfInstanceOf(type)); } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return true; + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java index 3a8bb2c..6d2464f 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java +++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -1314,4 +1314,8 @@ assert !instructionTypeCanThrow() || getPosition().isSome() || getPosition().isSyntheticNone(); return true; } + + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return false; + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java index 83e2bc3..dc02268 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java +++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -19,6 +19,7 @@ import com.android.tools.r8.ir.analysis.type.TypeLatticeElement; import com.android.tools.r8.ir.conversion.DexBuilder; import java.util.List; +import java.util.Set; public abstract class Invoke extends Instruction { @@ -269,4 +270,9 @@ } return TypeLatticeElement.fromDexType(returnType, Nullability.maybeNull(), appView); } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return getReturnType().isBooleanType(); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java b/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java index bf94a76..77394b1 100644 --- a/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java +++ b/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java
@@ -25,6 +25,7 @@ import com.android.tools.r8.ir.analysis.type.TypeLatticeElement; import com.android.tools.r8.ir.conversion.CfBuilder; import com.android.tools.r8.ir.conversion.DexBuilder; +import java.util.Set; public class NumberConversion extends Unop { @@ -155,4 +156,9 @@ public void buildCf(CfBuilder builder) { builder.add(new CfNumberConversion(from, to)); } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return to == NumericType.BYTE && source().knownToBeBoolean(seen); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Or.java b/src/main/java/com/android/tools/r8/ir/code/Or.java index 67b730f..78330a4 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Or.java +++ b/src/main/java/com/android/tools/r8/ir/code/Or.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.code.OrIntLit8; import com.android.tools.r8.code.OrLong; import com.android.tools.r8.code.OrLong2Addr; +import java.util.Set; public class Or extends LogicalBinop { @@ -86,4 +87,9 @@ CfLogicalBinop.Opcode getCfOpcode() { return CfLogicalBinop.Opcode.Or; } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return leftValue().knownToBeBoolean(seen) && rightValue().knownToBeBoolean(seen); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java index c0dac12..7dff8be 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Phi.java +++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -325,41 +325,6 @@ definitionUsers = null; } - /** - * Determine if the only possible values for the phi are the integers 0 or 1. - */ - @Override - public boolean knownToBeBoolean() { - return knownToBeBoolean(new HashSet<>()); - } - - private boolean knownToBeBoolean(HashSet<Phi> active) { - active.add(this); - - for (Value operand : operands) { - if (!operand.isPhi()) { - if (operand.isConstNumber()) { - ConstNumber number = operand.getConstInstruction().asConstNumber(); - if (!number.isIntegerOne() && !number.isIntegerZero()) { - return false; - } - } else { - return false; - } - } - } - - for (Value operand : operands) { - if (operand.isPhi() && !active.contains(operand.asPhi())) { - if (!operand.asPhi().knownToBeBoolean(active)) { - return false; - } - } - } - - return true; - } - @Override public boolean isConstant() { return false;
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java index c109441..83e593e 100644 --- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java +++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -27,6 +27,7 @@ import com.android.tools.r8.ir.conversion.DexBuilder; import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget; import com.android.tools.r8.ir.optimize.InliningConstraints; +import java.util.Set; import org.objectweb.asm.Opcodes; public class StaticGet extends FieldInstruction { @@ -182,4 +183,9 @@ return ClassInitializationAnalysis.InstructionUtils.forStaticGet( this, clazz, appView, mode, assumption); } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return getField().type.isBooleanType(); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java index ced7264..2243641 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Value.java +++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -209,7 +209,6 @@ private int needsRegister = -1; private boolean isThis = false; private boolean isArgument = false; - private boolean knownToBeBoolean = false; private LongInterval valueRange; private DebugData debugData; protected TypeLatticeElement typeLattice; @@ -815,22 +814,35 @@ return isArgument; } - public void setKnownToBeBoolean(boolean knownToBeBoolean) { - this.knownToBeBoolean = knownToBeBoolean; - } public boolean knownToBeBoolean() { - if (knownToBeBoolean) { + return knownToBeBoolean(null); + } + + public boolean knownToBeBoolean(Set<Phi> seen) { + if (!getTypeLattice().isInt()) { + return false; + } + + if (isPhi()) { + Phi self = this.asPhi(); + if (seen == null) { + seen = new HashSet<>(); + } + if (seen.contains(self)) { + return true; + } + seen.add(self); + for (Value operand : self.getOperands()) { + if (!operand.knownToBeBoolean(seen)) { + operand.knownToBeBoolean(seen); + return false; + } + } return true; } - if (getTypeLattice().isInt()) { - Value aliasedValue = getAliasedValue(); - if (!aliasedValue.isPhi() && aliasedValue.definition.isConstNumber()) { - ConstNumber definition = aliasedValue.definition.asConstNumber(); - return definition.isZero() || definition.getRawValue() == 1; - } - } - return false; + assert definition != null; + return definition.outTypeKnownToBeBoolean(seen); } public void markAsThis() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Xor.java b/src/main/java/com/android/tools/r8/ir/code/Xor.java index ec2d8db..3cf845a 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Xor.java +++ b/src/main/java/com/android/tools/r8/ir/code/Xor.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.code.XorIntLit8; import com.android.tools.r8.code.XorLong; import com.android.tools.r8.code.XorLong2Addr; +import java.util.Set; public class Xor extends LogicalBinop { @@ -86,4 +87,9 @@ CfLogicalBinop.Opcode getCfOpcode() { return CfLogicalBinop.Opcode.Xor; } + + @Override + public boolean outTypeKnownToBeBoolean(Set<Phi> seen) { + return leftValue().knownToBeBoolean(seen) && rightValue().knownToBeBoolean(seen); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java index 53750d6..8adb821 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -174,12 +174,17 @@ nextRemovedArgument = removedArgumentIterator.hasNext() ? removedArgumentIterator.next() : null; } else { + DexType dexType = method.method.proto.parameters.values[usedArgumentIndex++]; type = TypeLatticeElement.fromDexType( - method.method.proto.parameters.values[usedArgumentIndex++], + dexType, Nullability.maybeNull(), builder.appView); - builder.addNonThisArgument(register, type); + if (dexType.isBooleanType()) { + builder.addBooleanNonThisArgument(register); + } else { + builder.addNonThisArgument(register, type); + } } register += type.requiredRegisters(); }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java index bd7d27e..cbddf03 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -855,7 +855,7 @@ TypeLatticeElement receiver = TypeLatticeElement.fromDexType(method.method.holder, nullability, appView); Value value = writeRegister(register, receiver, ThrowingInfo.NO_THROW, local); - addInstruction(new Argument(value)); + addInstruction(new Argument(value, false)); value.markAsThis(); } @@ -864,7 +864,7 @@ if (removedArgumentInfo == null) { DebugLocalInfo local = getOutgoingLocal(register); Value value = writeRegister(register, typeLattice, ThrowingInfo.NO_THROW, local); - addInstruction(new Argument(value)); + addInstruction(new Argument(value, false)); } else { handleConstantOrUnusedArgument(register, removedArgumentInfo); } @@ -875,8 +875,8 @@ if (removedArgumentInfo == null) { DebugLocalInfo local = getOutgoingLocal(register); Value value = writeRegister(register, INT, ThrowingInfo.NO_THROW, local); - value.setKnownToBeBoolean(true); - addInstruction(new Argument(value)); + + addInstruction(new Argument(value, true)); } else { assert removedArgumentInfo.isNeverUsed(); } @@ -1005,7 +1005,6 @@ Value in2 = readRegister(index, ValueTypeConstraint.INT); TypeLatticeElement typeLattice = fromMemberType(type); Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW); - out.setKnownToBeBoolean(type == MemberType.BOOLEAN); ArrayGet instruction = new ArrayGet(type, out, in1, in2); assert instruction.instructionTypeCanThrow(); if (!type.isPrecise()) { @@ -1325,7 +1324,6 @@ dest, TypeLatticeElement.fromDexType(field.type, maybeNull(), appView), ThrowingInfo.CAN_THROW); - out.setKnownToBeBoolean(field.type == appView.dexItemFactory().booleanType); InstanceGet instruction = new InstanceGet(out, in, field); assert instruction.instructionTypeCanThrow(); addInstruction(instruction); @@ -1606,7 +1604,6 @@ dest, TypeLatticeElement.fromDexType(outType, maybeNull(), appView), ThrowingInfo.CAN_THROW); - outValue.setKnownToBeBoolean(outType.isBooleanType()); invoke.setOutValue(outValue); } @@ -1689,7 +1686,6 @@ dest, TypeLatticeElement.fromDexType(field.type, maybeNull(), appView), ThrowingInfo.CAN_THROW); - out.setKnownToBeBoolean(field.type == appView.dexItemFactory().booleanType); StaticGet instruction = new StaticGet(out, field); assert instruction.instructionTypeCanThrow(); addInstruction(instruction);
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 9d3954f..07e72b4 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
@@ -102,6 +102,11 @@ return ConstraintWithTarget.NEVER; } + if (appView.options().canHaveDalvikIntUsedAsBooleanBug() + && returnsIntAsBoolean(code, method, appView)) { + return ConstraintWithTarget.NEVER; + } + ConstraintWithTarget result = ConstraintWithTarget.ALWAYS; InliningConstraints inliningConstraints = new InliningConstraints(appView, GraphLense.getIdentityLense()); @@ -120,6 +125,22 @@ return result; } + private boolean returnsIntAsBoolean(IRCode code, DexEncodedMethod method, AppView appView) { + DexType returnType = method.method.proto.returnType; + for (BasicBlock basicBlock : code.blocks) { + InstructionListIterator instructionListIterator = basicBlock.listIterator(); + while (instructionListIterator.hasNext()) { + Instruction instruction = instructionListIterator.nextUntil(Instruction::isReturn); + if (instruction != null) { + if (returnType.isBooleanType() && !instruction.inValues().get(0).knownToBeBoolean()) { + return true; + } + } + } + } + return false; + } + boolean hasInliningAccess(DexEncodedMethod method, DexEncodedMethod target) { if (!isVisibleWithFlags(target.method.holder, method.method.holder, target.accessFlags)) { return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java index 33c8c96..2fe484e 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -1458,9 +1458,13 @@ public void buildPrelude(IRBuilder builder) { // Fill in the Argument instructions in the argument block. for (int i = 0; i < outline.argumentTypes.size(); i++) { - TypeLatticeElement typeLattice = - TypeLatticeElement.fromDexType(outline.argumentTypes.get(i), maybeNull(), appView); - builder.addNonThisArgument(i, typeLattice); + if (outline.argumentTypes.get(i).isBooleanType()) { + builder.addBooleanNonThisArgument(i); + } else { + TypeLatticeElement typeLattice = + TypeLatticeElement.fromDexType(outline.argumentTypes.get(i), maybeNull(), appView); + builder.addNonThisArgument(i, typeLattice); + } } builder.flushArgumentInstructions(); }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java index a75b3bc..a833241 100644 --- a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java +++ b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
@@ -191,7 +191,7 @@ TypeLatticeElement.fromDexType( receiver, Nullability.definitelyNotNull(), builder.appView), NO_THROW); - builder.add(new Argument(receiverValue)); + builder.add(new Argument(receiverValue, false)); receiverValue.markAsThis(); } @@ -203,7 +203,7 @@ TypeLatticeElement.fromDexType(parameters[i], Nullability.maybeNull(), builder.appView); Value paramValue = builder.writeRegister(paramRegisters[i], typeLattice, NO_THROW); paramValues[i] = paramValue; - builder.add(new Argument(paramValue)); + builder.add(new Argument(paramValue, parameters[i].isBooleanType())); } }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java index 951feef..2d3100c 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1104,7 +1104,7 @@ // // See b/131349148 public boolean canHaveDalvikCatchHandlerVerificationBug() { - return minApiLevel < AndroidApiLevel.L.getLevel(); + return isGeneratingClassFiles() || minApiLevel < AndroidApiLevel.L.getLevel(); } // Having an invoke instruction that targets an abstract method on a non-abstract class will fail @@ -1114,4 +1114,14 @@ public boolean canHaveDalvikAbstractMethodOnNonAbstractClassVerificationBug() { return minApiLevel < AndroidApiLevel.L.getLevel(); } + + // On dalvik we see issues if we inline the following method into the call site: + // public int value; + // public boolean getValue() { + // return value; + // } + // See b/134304597 + public boolean canHaveDalvikIntUsedAsBooleanBug() { + return isGeneratingClassFiles() || minApiLevel < AndroidApiLevel.L.getLevel(); + } }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java index 059501b..48a8246 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
@@ -136,7 +136,7 @@ TypeLatticeElement.fromDexType( app.dexItemFactory.throwableType, Nullability.definitelyNotNull(), appView), null); - instruction = new Argument(value); + instruction = new Argument(value, false); instruction.setPosition(position); block0.add(instruction); instruction = new If(Type.EQ, value);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/Main.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/Main.java new file mode 100644 index 0000000..384d500 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/Main.java
@@ -0,0 +1,15 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.ir.optimize.inliner.Regress134304597; + +public class Main { + public static void main(String[] args) { + Test a = new Test(); + if (args.length > 10) { + a.printValue(); + } + + System.out.println(a.getValue()); + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test.java new file mode 100644 index 0000000..979cb6d --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test.java
@@ -0,0 +1,22 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.ir.optimize.inliner.Regress134304597; + +class Test { + public int i = 33; + private int j = 42; + + Test() { + i = System.currentTimeMillis() == 42 ? 0 : 1; + j = i + 3; + } + + public boolean getValue() { + return i > 0; + } + + public void printValue() { + System.out.println(j); + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/TestDump.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/TestDump.java new file mode 100644 index 0000000..1683e4b --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/TestDump.java
@@ -0,0 +1,152 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.ir.optimize.inliner.Regress134304597; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class TestDump implements Opcodes { + + + // Generated from Test.java with tools/asmifier.py. Change commented out below + public static byte[] dump() throws Exception { + + ClassWriter classWriter = new ClassWriter(0); + FieldVisitor fieldVisitor; + MethodVisitor methodVisitor; + AnnotationVisitor annotationVisitor0; + + classWriter + .visit(V1_8, ACC_SUPER, "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", + null, "java/lang/Object", null); + + classWriter.visitSource("Test.java", null); + + { + fieldVisitor = classWriter.visitField(ACC_PUBLIC, "i", "I", null, null); + fieldVisitor.visitEnd(); + } + { + fieldVisitor = classWriter.visitField(ACC_PRIVATE, "j", "I", null, null); + fieldVisitor.visitEnd(); + } + { + methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null); + methodVisitor.visitCode(); + Label label0 = new Label(); + methodVisitor.visitLabel(label0); + methodVisitor.visitLineNumber(7, label0); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); + Label label1 = new Label(); + methodVisitor.visitLabel(label1); + methodVisitor.visitLineNumber(4, label1); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitIntInsn(BIPUSH, 33); + methodVisitor.visitFieldInsn(PUTFIELD, + "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", "i", "I"); + Label label2 = new Label(); + methodVisitor.visitLabel(label2); + methodVisitor.visitLineNumber(5, label2); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitIntInsn(BIPUSH, 42); + methodVisitor.visitFieldInsn(PUTFIELD, + "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", "j", "I"); + Label label3 = new Label(); + methodVisitor.visitLabel(label3); + methodVisitor.visitLineNumber(8, label3); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor + .visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false); + methodVisitor.visitLdcInsn(new Long(42L)); + methodVisitor.visitInsn(LCMP); + Label label4 = new Label(); + methodVisitor.visitJumpInsn(IFNE, label4); + methodVisitor.visitInsn(ICONST_0); + Label label5 = new Label(); + methodVisitor.visitJumpInsn(GOTO, label5); + methodVisitor.visitLabel(label4); + methodVisitor.visitFrame(Opcodes.F_FULL, 1, + new Object[]{"com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test"}, 1, + new Object[]{"com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test"}); + methodVisitor.visitIntInsn(BIPUSH, 1); + methodVisitor.visitLabel(label5); + methodVisitor.visitFrame(Opcodes.F_FULL, 1, + new Object[]{"com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test"}, 2, + new Object[]{"com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", + Opcodes.INTEGER}); + methodVisitor.visitFieldInsn(PUTFIELD, + "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", "i", "I"); + Label label6 = new Label(); + methodVisitor.visitLabel(label6); + methodVisitor.visitLineNumber(9, label6); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitFieldInsn(GETFIELD, + "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", "i", "I"); + methodVisitor.visitInsn(ICONST_3); + methodVisitor.visitInsn(IADD); + methodVisitor.visitFieldInsn(PUTFIELD, + "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", "j", "I"); + Label label7 = new Label(); + methodVisitor.visitLabel(label7); + methodVisitor.visitLineNumber(10, label7); + methodVisitor.visitInsn(RETURN); + methodVisitor.visitMaxs(5, 1); + methodVisitor.visitEnd(); + } + { + methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "getValue", "()Z", null, null); + methodVisitor.visitCode(); + Label label0 = new Label(); + methodVisitor.visitLabel(label0); + methodVisitor.visitLineNumber(13, label0); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitFieldInsn(GETFIELD, + "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", "i", "I"); + // Removed code to change: + // if (i > 0) return true; + // into + // return i; + /* Label label1 = new Label(); + methodVisitor.visitJumpInsn(IFLE, label1); + methodVisitor.visitInsn(ICONST_1); + Label label2 = new Label(); + methodVisitor.visitJumpInsn(GOTO, label2); + methodVisitor.visitLabel(label1); + methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + methodVisitor.visitInsn(ICONST_0); + methodVisitor.visitLabel(label2); + methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{Opcodes.INTEGER});*/ + methodVisitor.visitInsn(IRETURN); + methodVisitor.visitMaxs(1, 1); + methodVisitor.visitEnd(); + } + { + methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "printValue", "()V", null, null); + methodVisitor.visitCode(); + Label label0 = new Label(); + methodVisitor.visitLabel(label0); + methodVisitor.visitLineNumber(17, label0); + methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitFieldInsn(GETFIELD, + "com/android/tools/r8/ir/optimize/inliner/Regress134304597/Test", "j", "I"); + methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V", false); + Label label1 = new Label(); + methodVisitor.visitLabel(label1); + methodVisitor.visitLineNumber(18, label1); + methodVisitor.visitInsn(RETURN); + methodVisitor.visitMaxs(2, 1); + methodVisitor.visitEnd(); + } + classWriter.visitEnd(); + + return classWriter.toByteArray(); + } +} \ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/TestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/TestRunner.java new file mode 100644 index 0000000..d59a8ba --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress134304597/TestRunner.java
@@ -0,0 +1,41 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.ir.optimize.inliner.Regress134304597; + +import com.android.tools.r8.R8TestRunResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompileResult; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.AndroidApiLevel; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class TestRunner extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection params() { + return getTestParameters().withAllRuntimes().withAllApiLevels().build(); + } + + public TestRunner(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void TestInlineIntForBoolean() throws Exception { + testForR8(parameters.getBackend()) + .addProgramClasses(Main.class) + .addProgramClassFileData(TestDump.dump()) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("true"); + } +}