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");
+ }
+}