Merge "Raise an internal error if force inlining may not happen."
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 1fa0b29..16f5f2e 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.4.4-dev";
+ public static final String LABEL = "1.4.5-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 357de74..9500f9a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -822,7 +822,12 @@
private TrivialInitializer trivialInitializerInfo = null;
private boolean initializerEnablingJavaAssertions = false;
private ParameterUsagesInfo parametersUsages = null;
- private BitSet kotlinNotNullParamHints = null;
+ // Stores information about nullability hint per parameter. If set, that means, the method
+ // somehow (e.g., null check, such as arg != null, or using checkParameterIsNotNull) ensures
+ // the corresponding parameter is not null, or throws NPE before any other side effects.
+ // TODO(b/71500340): We call this *hint* because it does not 100% guarantee that a parameter is
+ // not null when the method returns normally. Maybe nonNullParamOnNormalExit in the future.
+ private BitSet nonNullParamHints = null;
private OptimizationInfo() {
// Intentionally left empty.
@@ -848,12 +853,12 @@
return parametersUsages == null ? null : parametersUsages.getParameterUsage(parameter);
}
- public BitSet getKotlinNotNullParamHints() {
- return kotlinNotNullParamHints;
+ public BitSet getNonNullParamHints() {
+ return nonNullParamHints;
}
- public void setKotlinNotNullParamHints(BitSet hints) {
- this.kotlinNotNullParamHints = hints;
+ public void setNonNullParamHints(BitSet hints) {
+ this.nonNullParamHints = hints;
}
public boolean returnsArgument() {
@@ -1037,8 +1042,8 @@
ensureMutableOI().setParameterUsages(parametersUsages);
}
- synchronized public void setKotlinNotNullParamHints(BitSet hints) {
- ensureMutableOI().setKotlinNotNullParamHints(hints);
+ synchronized public void setNonNullParamHints(BitSet hints) {
+ ensureMutableOI().setNonNullParamHints(hints);
}
synchronized public void setTrivialInitializer(TrivialInitializer info) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 1ee16fb..3d5c58d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -160,6 +160,8 @@
public final DexString methodHandleDescriptor = createString("Ljava/lang/invoke/MethodHandle;");
public final DexString methodTypeDescriptor = createString("Ljava/lang/invoke/MethodType;");
+ public final DexString npeDescriptor = createString("Ljava/lang/NullPointerException;");
+
public final DexString intFieldUpdaterDescriptor =
createString("Ljava/util/concurrent/atomic/AtomicIntegerFieldUpdater;");
public final DexString longFieldUpdaterDescriptor =
@@ -215,6 +217,8 @@
public final DexType methodHandleType = createType(methodHandleDescriptor);
public final DexType methodTypeType = createType(methodTypeDescriptor);
+ public final DexType npeType = createType(npeDescriptor);
+
public final StringBuildingMethods stringBuilderMethods =
new StringBuildingMethods(stringBuilderType);
public final StringBuildingMethods stringBufferMethods =
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index f49115a..c628893 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -553,6 +553,9 @@
}
public DexType computeLeastUpperBoundOfClasses(AppInfo appInfo, DexType other) {
+ if (this == other) {
+ return this;
+ }
DexType objectType = appInfo.dexItemFactory.objectType;
// If we have no definition for either class, stop proceeding.
if (hierarchyLevel == UNKNOWN_LEVEL || other.hierarchyLevel == UNKNOWN_LEVEL) {
@@ -561,10 +564,6 @@
if (this == objectType || other == objectType) {
return objectType;
}
- if (this == other) {
- return this;
- }
-
DexType t1;
DexType t2;
if (other.hierarchyLevel < this.hierarchyLevel) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Add.java b/src/main/java/com/android/tools/r8/ir/code/Add.java
index d5896da..2a8da38 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Add.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Add.java
@@ -83,11 +83,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asAdd().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left + right;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java
index bff16af..9c3e58d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java
@@ -42,11 +42,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java
index aa14475..49f144e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingNop.java
@@ -40,11 +40,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java
index 91be1a4..c7d617b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java
+++ b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingUser.java
@@ -40,11 +40,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
assert inValues.get(0).definition instanceof AlwaysMaterializingDefinition;
return inValues.get(0).definition.maxOutValueRegister();
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 283f369..73d3158 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
@@ -69,11 +69,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asAnd().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left & right;
}
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 cf52e26..92e16f4 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
@@ -56,12 +56,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isArgument();
- return 0;
- }
-
- @Override
public boolean isArgument() {
return true;
}
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 4254eef..b7286f8 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
@@ -101,11 +101,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asArrayGet().type.ordinal();
- }
-
- @Override
public int maxInValueRegister() {
return Constants.U8BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index e222eaa..709ac0e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -82,12 +82,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isArrayLength();
- return 0;
- }
-
- @Override
public ConstraintWithTarget inliningConstraint(
InliningConstraints inliningConstraints, DexType invocationContext) {
return inliningConstraints.forArrayLength();
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index f27d55f..31ec3df 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -139,11 +139,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asArrayPut().type.ordinal();
- }
-
- @Override
public boolean isArrayPut() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
index 03d718f..bb61b03 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
@@ -77,11 +77,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.slowCompareTo(other.asCheckCast().type);
- }
-
- @Override
public int maxInValueRegister() {
return Constants.U8BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Cmp.java b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
index 4c2529d..2f346a5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Cmp.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
@@ -127,11 +127,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return bias.ordinal() - other.asCmp().bias.ordinal();
- }
-
- @Override
public int maxInValueRegister() {
return Constants.U8BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index e612448..6f1b171 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -86,11 +86,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return clazz.slowCompareTo(other.asConstClass().clazz);
- }
-
- @Override
public boolean canBeDeadCode(IRCode code, InternalOptions options) {
// A const-class instruction can be dead code only if the resulting program is known to contain
// the class mentioned.
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
index 4f6b20e..e0b57f1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
@@ -62,11 +62,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return methodHandle.slowCompareTo(other.asConstMethodHandle().methodHandle);
- }
-
- @Override
public int maxInValueRegister() {
assert false : "ConstMethodHandle has no register arguments.";
return 0;
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
index 584b109..fb23503 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
@@ -62,11 +62,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return methodType.slowCompareTo(other.asConstMethodType().methodType);
- }
-
- @Override
public int maxInValueRegister() {
assert false : "ConstMethodType has no register arguments.";
return 0;
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 1f31c3a..c09b6aa 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
@@ -215,17 +215,6 @@
return o.outType() == outType() && o.value == value;
}
- @Override
- public int compareNonValueParts(Instruction other) {
- ConstNumber o = other.asConstNumber();
- int result;
- result = outType().ordinal() - o.outType().ordinal();
- if (result != 0) {
- return result;
- }
- return Long.signum(value - o.value);
- }
-
public boolean is8Bit() {
return NumberUtils.is8Bit(value);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index 596bd81..f55d35f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -58,11 +58,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return value.slowCompareTo(other.asConstString().value);
- }
-
- @Override
public int maxInValueRegister() {
assert false : "ConstString has no register arguments.";
return 0;
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
index c7a45f2..ca9063d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
@@ -45,11 +45,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java
index c956593..34ca368 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalsChange.java
@@ -74,12 +74,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isDebugLocalsChange();
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
index 0fcc466..c373853 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
@@ -41,12 +41,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isDebugPosition();
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Div.java b/src/main/java/com/android/tools/r8/ir/code/Div.java
index 6c9537a..60daec0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Div.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Div.java
@@ -95,11 +95,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asDiv().type.ordinal();
- }
-
- @Override
public boolean canBeFolded() {
return super.canBeFolded() && !rightValue().isZero();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Dup.java b/src/main/java/com/android/tools/r8/ir/code/Dup.java
index 640d24c..090099e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Dup.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Dup.java
@@ -16,11 +16,41 @@
public class Dup extends Instruction {
- public Dup(StackValues dest, StackValue src) {
+ public Dup(StackValue destBottom, StackValue destTop, StackValue src) {
+ this(new StackValues(destBottom, destTop), src);
+ }
+
+ private Dup(StackValues dest, StackValue src) {
super(dest, src);
}
@Override
+ public void setOutValue(Value value) {
+ assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed() ||
+ value instanceof StackValues;
+ this.outValue = value;
+ for (StackValue val : ((StackValues)value).getStackValues()) {
+ val.definition = this;
+ }
+ }
+
+ private StackValue[] getStackValues() {
+ return ((StackValues) outValue()).getStackValues();
+ }
+
+ public StackValue outBottom() {
+ return getStackValues()[0];
+ }
+
+ public StackValue outTop() {
+ return getStackValues()[1];
+ }
+
+ public StackValue src() {
+ return (StackValue) inValues.get(0);
+ }
+
+ @Override
public void buildDex(DexBuilder builder) {
throw new Unreachable("This classfile-specific IR should not be inserted in the Dex backend.");
}
@@ -40,11 +70,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- throw new Unreachable();
- }
-
- @Override
public int maxInValueRegister() {
return 0;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Dup2.java b/src/main/java/com/android/tools/r8/ir/code/Dup2.java
index decbaec..a682dc6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Dup2.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Dup2.java
@@ -17,11 +17,54 @@
public class Dup2 extends Instruction {
- public Dup2(StackValues dest, StackValue src1, StackValue src2) {
- super(dest, ImmutableList.of(src1, src2));
- assert !src1.getTypeLattice().isWide();
- assert !src2.getTypeLattice().isWide();
- assert dest.getStackValues().size() == 4;
+ public Dup2(
+ StackValue destTowMinusThree,
+ StackValue destTopMinusTwo,
+ StackValue destTopMinusOne,
+ StackValue destTop,
+ StackValue srcBottom,
+ StackValue srcTop) {
+ this(
+ new StackValues(destTowMinusThree, destTopMinusTwo, destTopMinusOne, destTop),
+ srcBottom,
+ srcTop);
+ }
+
+ private Dup2(StackValues dest, StackValue srcBottom, StackValue srcTop) {
+ super(dest, ImmutableList.of(srcBottom, srcTop));
+ assert !srcBottom.getTypeLattice().isWide();
+ assert !srcTop.getTypeLattice().isWide();
+ assert dest.getStackValues().length == 4;
+ }
+
+ @Override
+ public void setOutValue(Value value) {
+ assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed() ||
+ value instanceof StackValues;
+ this.outValue = value;
+ for (StackValue val : ((StackValues)value).getStackValues()) {
+ val.definition = this;
+ }
+ }
+
+ private StackValue[] getStackValues() {
+ return ((StackValues) outValue()).getStackValues();
+ }
+
+ public StackValue outTopMinusThree() {
+ return getStackValues()[0];
+ }
+
+ public StackValue outTopMinusTwo() {
+ return getStackValues()[1];
+ }
+
+ public StackValue outTopMinusOne() {
+ return getStackValues()[2];
+ }
+
+ public StackValue outTop() {
+ return getStackValues()[3];
}
@Override
@@ -40,11 +83,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- throw new Unreachable();
- }
-
- @Override
public int maxInValueRegister() {
return 0;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Goto.java b/src/main/java/com/android/tools/r8/ir/code/Goto.java
index 972d2d2..dfe5b28 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Goto.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Goto.java
@@ -76,13 +76,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isGoto();
- assert false : "Not supported";
- return 0;
- }
-
- @Override
public boolean isGoto() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/If.java b/src/main/java/com/android/tools/r8/ir/code/If.java
index 4fdb047..025dce9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/If.java
+++ b/src/main/java/com/android/tools/r8/ir/code/If.java
@@ -164,13 +164,6 @@
&& o.type == type;
}
- @Override
- public int compareNonValueParts(Instruction other) {
- assert other.isIf();
- assert false : "Not supported";
- return 0;
- }
-
public BasicBlock targetFromCondition(ConstNumber value) {
assert isZeroTest();
assert value.outType() == ValueType.INT
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 3d30b82..a8bbcb3 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
@@ -103,16 +103,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- InstanceGet o = other.asInstanceGet();
- int result = field.slowCompareTo(o.field);
- if (result != 0) {
- return result;
- }
- return type.ordinal() - o.type.ordinal();
- }
-
- @Override
public ConstraintWithTarget inliningConstraint(
InliningConstraints inliningConstraints, DexType invocationContext) {
return inliningConstraints.forInstanceGet(field, invocationContext);
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 8e2446b..917c7fc 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
@@ -64,11 +64,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.slowCompareTo(other.asInstanceOf().type);
- }
-
- @Override
public boolean isInstanceOf() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index e8d917d..0ad8544 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -92,16 +92,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- InstancePut o = other.asInstancePut();
- int result = field.slowCompareTo(o.field);
- if (result != 0) {
- return result;
- }
- return type.ordinal() - o.type.ordinal();
- }
-
- @Override
public int maxInValueRegister() {
return Constants.U4BIT_MAX;
}
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 d4229bd..cda1c48 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
@@ -345,8 +345,6 @@
return position.equals(other.position) && identicalNonValueNonPositionParts(other);
}
- public abstract int compareNonValueParts(Instruction other);
-
private boolean identicalInputAfterRegisterAllocation(
Value a, int aInstrNumber, Instruction bInstr, Value b, int bInstrNumber,
RegisterAllocator allocator) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
index 1b03815..bb42328 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -84,13 +84,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isInvokeCustom();
- assert false : "Not supported";
- return 0;
- }
-
- @Override
public boolean isInvokeCustom() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 9689d22..060f1d8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -39,11 +39,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return getInvokedMethod().slowCompareTo(other.asInvokeMethod().getInvokedMethod());
- }
-
- @Override
public String toString() {
return super.toString() + "; method: " + method.toSourceString();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
index 002fa9d..cfd3b1d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
@@ -60,14 +60,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- if (!other.isInvokeMultiNewArray()) {
- return -1;
- }
- return type.slowCompareTo(other.asInvokeMultiNewArray().type);
- }
-
- @Override
public ConstraintWithTarget inliningConstraint(
InliningConstraints inliningConstraints, DexType invocationContext) {
return inliningConstraints.forInvokeMultiNewArray(type, invocationContext);
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index b071703..df74e17 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -80,14 +80,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- if (!other.isInvokeNewArray()) {
- return -1;
- }
- return type.slowCompareTo(other.asInvokeNewArray().type);
- }
-
- @Override
public boolean isInvokeNewArray() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Load.java b/src/main/java/com/android/tools/r8/ir/code/Load.java
index 4a6817f..fb1c0ef 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Load.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Load.java
@@ -42,11 +42,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
return Constants.U16BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Monitor.java b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
index eb1c030..766da27 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Monitor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
@@ -66,11 +66,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asMonitor().type.ordinal();
- }
-
- @Override
public int maxInValueRegister() {
return U8BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Move.java b/src/main/java/com/android/tools/r8/ir/code/Move.java
index 7c9dcca..0ee6178 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Move.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Move.java
@@ -67,12 +67,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isMove();
- return 0;
- }
-
- @Override
public String toString() {
return super.toString() + " (" + outType() + ")";
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index 8166f6e..8bbb672 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -53,12 +53,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isMoveException();
- return 0;
- }
-
- @Override
public boolean isMoveException() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Mul.java b/src/main/java/com/android/tools/r8/ir/code/Mul.java
index 7407f2e..ebe12f8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Mul.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Mul.java
@@ -95,11 +95,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asMul().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left * right;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Neg.java b/src/main/java/com/android/tools/r8/ir/code/Neg.java
index 86e7440..856e2e0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Neg.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Neg.java
@@ -40,11 +40,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asNeg().type.ordinal();
- }
-
- @Override
public void buildDex(DexBuilder builder) {
com.android.tools.r8.code.Instruction instruction;
int dest = builder.allocatedRegister(dest(), getNumber());
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index c8f229a..95a9225 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -68,11 +68,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.slowCompareTo(other.asNewArrayEmpty().type);
- }
-
- @Override
public boolean isNewArrayEmpty() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index 0574e59..f0b1db9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -63,28 +63,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- NewArrayFilledData o = other.asNewArrayFilledData();
- int result;
- result = element_width - o.element_width;
- if (result != 0) {
- return result;
- }
- result = Long.signum(size - o.size);
- if (result != 0) {
- return result;
- }
- assert data.length == o.data.length;
- for (int i = 0; i < data.length; i++) {
- result = data[i] - o.data[i];
- if (result != 0) {
- return result;
- }
- }
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
return Constants.U8BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 18a60d4..747966c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -48,11 +48,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return clazz.slowCompareTo(other.asNewInstance().clazz);
- }
-
- @Override
public int maxInValueRegister() {
assert false : "NewInstance has no register arguments";
return 0;
diff --git a/src/main/java/com/android/tools/r8/ir/code/NonNull.java b/src/main/java/com/android/tools/r8/ir/code/NonNull.java
index 17bd113..55b9b67 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NonNull.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NonNull.java
@@ -78,12 +78,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other instanceof NonNull;
- return 0;
- }
-
- @Override
public ConstraintWithTarget inliningConstraint(
InliningConstraints inliningConstraints, DexType invocationContext) {
return inliningConstraints.forNonNull();
diff --git a/src/main/java/com/android/tools/r8/ir/code/Not.java b/src/main/java/com/android/tools/r8/ir/code/Not.java
index 1073f4e..013b219 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Not.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Not.java
@@ -74,11 +74,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asNot().type.ordinal();
- }
-
- @Override
public boolean isNot() {
return true;
}
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 d676216..fd9afa8 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
@@ -128,17 +128,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- NumberConversion o = other.asNumberConversion();
- int result;
- result = from.ordinal() - o.from.ordinal();
- if (result != 0) {
- return result;
- }
- return to.ordinal() - o.to.ordinal();
- }
-
- @Override
public boolean isNumberConversion() {
return true;
}
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 9136be3..fd4f204 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
@@ -68,11 +68,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asOr().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left | right;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Pop.java b/src/main/java/com/android/tools/r8/ir/code/Pop.java
index 9d63ee1..2598d55 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Pop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Pop.java
@@ -35,11 +35,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Rem.java b/src/main/java/com/android/tools/r8/ir/code/Rem.java
index 02eb712..bd838bc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Rem.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Rem.java
@@ -95,11 +95,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asRem().type.ordinal();
- }
-
- @Override
public boolean canBeFolded() {
return super.canBeFolded() && !rightValue().isZero();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index bb750c2..2bbb8c2 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -86,15 +86,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- if (isReturnVoid()) {
- return other.asReturn().isReturnVoid() ? 0 : -1;
- } else {
- return returnValue().type.ordinal() - other.asReturn().returnValue().type.ordinal();
- }
- }
-
- @Override
public int maxInValueRegister() {
return Constants.U8BIT_MAX;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Shl.java b/src/main/java/com/android/tools/r8/ir/code/Shl.java
index 57b3190..d9d0be0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Shl.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Shl.java
@@ -74,11 +74,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asShl().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left << right;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Shr.java b/src/main/java/com/android/tools/r8/ir/code/Shr.java
index 18c38ed..c930d1d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Shr.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Shr.java
@@ -74,11 +74,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asShr().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left >> right;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/StackValues.java b/src/main/java/com/android/tools/r8/ir/code/StackValues.java
index 79ca78b..5e0a979 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StackValues.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StackValues.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
-import java.util.List;
/**
* {@link StackValues} allow us to represent stack operations that produces two or more elements on
@@ -14,15 +13,15 @@
*/
public class StackValues extends Value {
- private final List<StackValue> stackValues;
+ private final StackValue[] stackValues;
- public StackValues(List<StackValue> stackValues) {
+ public StackValues(StackValue... stackValues) {
super(Value.UNDEFINED_NUMBER, TypeLatticeElement.BOTTOM, null);
this.stackValues = stackValues;
- assert stackValues.size() >= 2;
+ assert stackValues.length >= 2;
}
- public List<StackValue> getStackValues() {
+ public StackValue[] getStackValues() {
return stackValues;
}
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 e767246..b616d38 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
@@ -97,17 +97,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- StaticGet o = other.asStaticGet();
- int result;
- result = field.slowCompareTo(o.field);
- if (result != 0) {
- return result;
- }
- return type.ordinal() - o.type.ordinal();
- }
-
- @Override
public ConstraintWithTarget inliningConstraint(
InliningConstraints inliningConstraints, DexType invocationContext) {
return inliningConstraints.forStaticGet(field, invocationContext);
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index 8824d54..ef64300 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -96,17 +96,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- StaticPut o = other.asStaticPut();
- int result;
- result = field.slowCompareTo(o.field);
- if (result != 0) {
- return result;
- }
- return type.ordinal() - o.type.ordinal();
- }
-
- @Override
public ConstraintWithTarget inliningConstraint(
InliningConstraints inliningConstraints, DexType invocationContext) {
return inliningConstraints.forStaticPut(field, invocationContext);
diff --git a/src/main/java/com/android/tools/r8/ir/code/Store.java b/src/main/java/com/android/tools/r8/ir/code/Store.java
index 1e71f1e..070b308 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Store.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Store.java
@@ -44,11 +44,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return 0;
- }
-
- @Override
public int maxInValueRegister() {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Sub.java b/src/main/java/com/android/tools/r8/ir/code/Sub.java
index b263e63..7e7a9f8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Sub.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Sub.java
@@ -90,11 +90,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asSub().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left - right;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Swap.java b/src/main/java/com/android/tools/r8/ir/code/Swap.java
index 9e65d0f..29eb9eb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Swap.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Swap.java
@@ -17,15 +17,35 @@
public class Swap extends Instruction {
- public Swap(StackValues dest, StackValues src) {
- super(dest, src.getStackValues());
- assert src.getStackValues().size() == 2;
+ public Swap(StackValue destBottom, StackValue destTop, StackValue srcBottom, StackValue srcTop) {
+ this(new StackValues(destBottom, destTop), srcBottom, srcTop);
+ }
+
+ private Swap(StackValues dest, StackValue src1, StackValue src2) {
+ super(dest, ImmutableList.of(src1, src2));
assert !this.inValues.get(0).type.isWide() && !this.inValues.get(1).type.isWide();
}
- public Swap(StackValues dest, StackValue src1, StackValue src2) {
- super(dest, ImmutableList.of(src1, src2));
- assert !this.inValues.get(0).type.isWide() && !this.inValues.get(1).type.isWide();
+ @Override
+ public void setOutValue(Value value) {
+ assert outValue == null || !outValue.hasUsersInfo() || !outValue.isUsed() ||
+ value instanceof StackValues;
+ this.outValue = value;
+ for (StackValue val : ((StackValues)value).getStackValues()) {
+ val.definition = this;
+ }
+ }
+
+ private StackValue[] getStackValues() {
+ return ((StackValues) outValue()).getStackValues();
+ }
+
+ public StackValue outBottom() {
+ return getStackValues()[0];
+ }
+
+ public StackValue outTop() {
+ return getStackValues()[1];
}
@Override
@@ -44,11 +64,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- throw new Unreachable();
- }
-
- @Override
public int maxInValueRegister() {
return 0;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Switch.java b/src/main/java/com/android/tools/r8/ir/code/Switch.java
index 871500c..fb45d97 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Switch.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Switch.java
@@ -153,12 +153,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isSwitch();
- return 0;
- }
-
- @Override
public void buildDex(DexBuilder builder) {
int value = builder.allocatedRegister(value(), getNumber());
if (emitPacked()) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Throw.java b/src/main/java/com/android/tools/r8/ir/code/Throw.java
index 7bda1c8..eede2da 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Throw.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Throw.java
@@ -49,12 +49,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- assert other.isThrow();
- return 0;
- }
-
- @Override
public boolean isThrow() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Ushr.java b/src/main/java/com/android/tools/r8/ir/code/Ushr.java
index d1e5a69..65c932c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Ushr.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Ushr.java
@@ -74,11 +74,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asUshr().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left >>> right;
}
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 2e9c497..f3b8858 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
@@ -68,11 +68,6 @@
}
@Override
- public int compareNonValueParts(Instruction other) {
- return type.ordinal() - other.asXor().type.ordinal();
- }
-
- @Override
int foldIntegers(int left, int right) {
return left ^ right;
}
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 d02bdc7..540eacb 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
@@ -5,6 +5,7 @@
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
+import static com.android.tools.r8.ir.optimize.CodeRewriter.checksNullReceiverBeforeSideEffect;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
@@ -71,6 +72,7 @@
import com.google.common.base.Suppliers;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
@@ -276,10 +278,11 @@
}
}
- private void synthesizeLambdaClasses(Builder<?> builder) {
+ private void synthesizeLambdaClasses(Builder<?> builder, ExecutorService executorService)
+ throws ExecutionException {
if (lambdaRewriter != null) {
lambdaRewriter.adjustAccessibility();
- lambdaRewriter.synthesizeLambdaClasses(builder);
+ lambdaRewriter.synthesizeLambdaClasses(builder, executorService);
}
}
@@ -297,9 +300,13 @@
}
private void desugarInterfaceMethods(
- Builder<?> builder, InterfaceMethodRewriter.Flavor includeAllResources) {
+ Builder<?> builder,
+ InterfaceMethodRewriter.Flavor includeAllResources,
+ ExecutorService executorService)
+ throws ExecutionException {
if (interfaceMethodRewriter != null) {
- interfaceMethodRewriter.desugarInterfaceMethods(builder, includeAllResources);
+ interfaceMethodRewriter.desugarInterfaceMethods(
+ builder, includeAllResources, executorService);
}
}
@@ -326,8 +333,8 @@
Builder<?> builder = application.builder();
builder.setHighestSortingString(highestSortingString);
- synthesizeLambdaClasses(builder);
- desugarInterfaceMethods(builder, ExcludeDexResources);
+ synthesizeLambdaClasses(builder, executor);
+ desugarInterfaceMethods(builder, ExcludeDexResources, executor);
synthesizeTwrCloseResourceUtilityClass(builder);
processCovariantReturnTypeAnnotations(builder);
@@ -499,8 +506,8 @@
inliner.processDoubleInlineCallers(this, directFeedback);
}
- synthesizeLambdaClasses(builder);
- desugarInterfaceMethods(builder, IncludeAllResources);
+ synthesizeLambdaClasses(builder, executorService);
+ desugarInterfaceMethods(builder, IncludeAllResources, executorService);
synthesizeTwrCloseResourceUtilityClass(builder);
handleSynthesizedClassMapping(builder);
@@ -650,6 +657,24 @@
}
}
+ public void optimizeSynthesizedClasses(
+ Collection<DexProgramClass> classes, ExecutorService executorService)
+ throws ExecutionException {
+ Set<DexEncodedMethod> methods = Sets.newIdentityHashSet();
+ try {
+ for (DexProgramClass clazz : classes) {
+ enterCachedClass(clazz);
+ clazz.forEachMethod(methods::add);
+ }
+ // Process the generated class, but don't apply any outlining.
+ optimizeSynthesizedMethods(methods, executorService);
+ } finally {
+ for (DexProgramClass clazz : classes) {
+ leaveCachedClass(clazz);
+ }
+ }
+ }
+
public void optimizeMethodOnSynthesizedClass(DexProgramClass clazz, DexEncodedMethod method) {
if (!method.isProcessed()) {
try {
@@ -670,6 +695,26 @@
}
}
+ public void optimizeSynthesizedMethods(
+ Collection<DexEncodedMethod> methods, ExecutorService executorService)
+ throws ExecutionException {
+ List<Future<?>> futures = new ArrayList<>();
+ for (DexEncodedMethod method : methods) {
+ futures.add(
+ executorService.submit(
+ () -> {
+ processMethod(
+ method,
+ ignoreOptimizationFeedback,
+ methods::contains,
+ CallSiteInformation.empty(),
+ Outliner::noProcessing);
+ return null; // we want a Callable not a Runnable to be able to throw
+ }));
+ }
+ ThreadUtils.awaitFutures(futures);
+ }
+
private void enterCachedClass(DexProgramClass clazz) {
DexProgramClass previous = cachedClasses.put(clazz.type, clazz);
assert previous == null;
@@ -740,7 +785,7 @@
printMethod(code, "Initial IR (SSA)");
if (method.getCode() != null && method.getCode().isJarCode()) {
- computeKotlinNotNullParamHints(feedback, method, code);
+ computeKotlinNonNullParamHints(feedback, method, code);
}
if (options.canHaveArtStringNewInitBug()) {
@@ -886,6 +931,11 @@
if (options.enableInlining && inliner != null) {
codeRewriter.identifyInvokeSemanticsForInlining(method, code, feedback);
}
+ // If hints from Kotlin metadata or use of Kotlin Intrinsics were not available, track usage of
+ // parameters and compute their nullability.
+ if (method.getOptimizationInfo().getNonNullParamHints() == null) {
+ computeNonNullParamHints(feedback, method, code);
+ }
// Insert code to log arguments if requested.
if (options.methodMatchesLogArgumentsFilter(method)) {
@@ -911,7 +961,7 @@
finalizeIR(method, code, feedback);
}
- private void computeKotlinNotNullParamHints(
+ private void computeKotlinNonNullParamHints(
OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
DexMethod originalSignature = graphLense().getOriginalMethodSignature(method.method);
DexClass originalHolder = definitionFor(originalSignature.holder);
@@ -927,7 +977,7 @@
originalSignature.name.toString(), originalSignature.proto.toDescriptorString());
if (hintFromMetadata != null) {
if (hintFromMetadata.length() > 0) {
- feedback.setKotlinNotNullParamHints(method, hintFromMetadata);
+ feedback.setNonNullParamHints(method, hintFromMetadata);
}
return;
}
@@ -959,7 +1009,28 @@
}
}
if (paramsCheckedForNull.length() > 0) {
- feedback.setKotlinNotNullParamHints(method, paramsCheckedForNull);
+ feedback.setNonNullParamHints(method, paramsCheckedForNull);
+ }
+ }
+
+ private void computeNonNullParamHints(
+ OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
+ List<Value> arguments = code.collectArguments(true);
+ BitSet paramsCheckedForNull = new BitSet();
+ for (int index = 0; index < arguments.size(); index++) {
+ Value argument = arguments.get(index);
+ if (argument.isUsed()
+ && checksNullReceiverBeforeSideEffect(code, appInfo.dexItemFactory, argument)) {
+ paramsCheckedForNull.set(index);
+ }
+ // TODO(b/71500340): More sophisticated analysis?
+ // The above one only catches something like:
+ // if (param == null) return;
+ // throw new NPE;
+ // which is good enough to handle Intrinsics.checkParameterIsNotNull(param, message)
+ }
+ if (paramsCheckedForNull.length() > 0) {
+ feedback.setNonNullParamHints(method, paramsCheckedForNull);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 4e6cbf4..5046513 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -531,7 +531,7 @@
currentPosition = getCanonicalDebugPositionAtOffset(instructionIndex);
}
- String preInstructionState;
+ String preInstructionState = "";
if (Log.ENABLED) {
preInstructionState = state.toString();
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
index 0833579..102130c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
@@ -23,5 +23,5 @@
void setTrivialInitializer(DexEncodedMethod method, TrivialInitializer info);
void setInitializerEnablingJavaAssertions(DexEncodedMethod method);
void setParameterUsages(DexEncodedMethod method, ParameterUsagesInfo parameterUsagesInfo);
- void setKotlinNotNullParamHints(DexEncodedMethod method, BitSet hints);
+ void setNonNullParamHints(DexEncodedMethod method, BitSet hints);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java
index 16267f6..8a37f3b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDirect.java
@@ -70,7 +70,7 @@
}
@Override
- public void setKotlinNotNullParamHints(DexEncodedMethod method, BitSet hints) {
- method.setKotlinNotNullParamHints(hints);
+ public void setNonNullParamHints(DexEncodedMethod method, BitSet hints) {
+ method.setNonNullParamHints(hints);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
index a27f200..28fb006 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
@@ -52,6 +52,6 @@
}
@Override
- public void setKotlinNotNullParamHints(DexEncodedMethod method, BitSet hints) {
+ public void setNonNullParamHints(DexEncodedMethod method, BitSet hints) {
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
index 2583f8f..449aede 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
@@ -71,7 +71,7 @@
}
@Override
- public void setKotlinNotNullParamHints(DexEncodedMethod method, BitSet hints) {
+ public void setNonNullParamHints(DexEncodedMethod method, BitSet hints) {
// Ignored.
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 0f6dbd7..7a19fb8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -37,6 +37,8 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
//
// Default and static interface method desugaring rewriter (note that lambda
@@ -374,7 +376,9 @@
* Move static and default interface methods to companion classes,
* add missing methods to forward to moved default methods implementation.
*/
- public void desugarInterfaceMethods(Builder<?> builder, Flavor flavour) {
+ public void desugarInterfaceMethods(
+ Builder<?> builder, Flavor flavour, ExecutorService executorService)
+ throws ExecutionException {
// Process all classes first. Add missing forwarding methods to
// replace desugared default interface methods.
synthesizedMethods.addAll(processClasses(builder, flavour));
@@ -391,9 +395,7 @@
builder.addSynthesizedClass(entry.getValue(), isInMainDexList(entry.getKey()));
}
- for (DexEncodedMethod method : synthesizedMethods) {
- converter.optimizeSynthesizedMethod(method);
- }
+ converter.optimizeSynthesizedMethods(synthesizedMethods, executorService);
// Cached data is not needed any more.
clear();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 22113f8..b89a185 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -29,12 +29,15 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
/**
* Lambda desugaring rewriter.
@@ -189,10 +192,14 @@
}
/** Generates lambda classes and adds them to the builder. */
- public void synthesizeLambdaClasses(Builder<?> builder) {
+ public void synthesizeLambdaClasses(Builder<?> builder, ExecutorService executorService)
+ throws ExecutionException {
+ converter.optimizeSynthesizedClasses(
+ knownLambdaClasses.values().stream()
+ .map(LambdaClass::getLambdaClass).collect(ImmutableSet.toImmutableSet()),
+ executorService);
for (LambdaClass lambdaClass : knownLambdaClasses.values()) {
DexProgramClass synthesizedClass = lambdaClass.getLambdaClass();
- converter.optimizeSynthesizedClass(synthesizedClass);
builder.addSynthesizedClass(synthesizedClass, lambdaClass.addToMainDexList.get());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 4b55228..b9e8c3e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -783,7 +783,8 @@
// Identifies if the method preserves null check of the receiver after inlining.
final Value receiver = code.getThis();
feedback.markCheckNullReceiverBeforeAnySideEffect(method,
- receiver.isUsed() && checksNullReceiverBeforeSideEffect(code, receiver));
+ receiver.isUsed()
+ && checksNullReceiverBeforeSideEffect(code, appInfo.dexItemFactory, receiver));
}
}
@@ -1096,6 +1097,7 @@
*/
private enum InstructionEffect {
DESIRED_EFFECT,
+ CONDITIONAL_EFFECT,
OTHER_EFFECT,
NO_EFFECT
}
@@ -1106,14 +1108,48 @@
*
* Note: we do not track phis so we may return false negative. This is a conservative approach.
*/
- private static boolean checksNullReceiverBeforeSideEffect(IRCode code, Value receiver) {
+ public static boolean checksNullReceiverBeforeSideEffect(
+ IRCode code, DexItemFactory factory, Value receiver) {
return alwaysTriggerExpectedEffectBeforeAnythingElse(code, instr -> {
+ BasicBlock currentBlock = instr.getBlock();
+ // If the code explicitly checks the nullability of receiver, we should visit the next block
+ // that corresponds to the null receiver where NPE semantic could be preserved.
+ if (!currentBlock.hasCatchHandlers() && isNullabilityCheck(instr, receiver)) {
+ return InstructionEffect.CONDITIONAL_EFFECT;
+ }
+ // In general, new-instance can raise ClassNotFoundException or OutOfMemoryError, hence
+ // OTHER_EFFECT. However, if the code is creating an instance of NPE and throwing it in the
+ // same block, that's another way of preserving NPE, if the predecessor checks nullability of
+ // the receiver.
+ if (instr.isNewInstance()) {
+ if (!currentBlock.hasCatchHandlers()
+ && instr.asNewInstance().clazz.equals(factory.npeType)) {
+ boolean isThowingInTheSameBlock = false;
+ for (Instruction user : instr.outValue().uniqueUsers()) {
+ if (user.isThrow() && user.getBlock().equals(currentBlock)) {
+ isThowingInTheSameBlock = true;
+ break;
+ }
+ }
+ // We found a NPE throwing code.
+ if (isThowingInTheSameBlock) {
+ // Combined with the above CONDITIONAL_EFFECT, the code checks NPE on receiver.
+ for (BasicBlock predecessor : currentBlock.getPredecessors()) {
+ Instruction last =
+ predecessor.listIterator(predecessor.getInstructions().size()).previous();
+ if (isNullabilityCheck(last, receiver)) {
+ return InstructionEffect.DESIRED_EFFECT;
+ }
+ }
+ }
+ }
+ }
if (instr.throwsNpeIfValueIsNull(receiver)) {
// In order to preserve NPE semantic, the exception must not be caught by any handler.
// Therefore, we must ignore this instruction if it is covered by a catch handler.
// Note: this is a conservative approach where we consider that any catch handler could
// catch the exception, even if it cannot catch a NullPointerException.
- if (!instr.getBlock().hasCatchHandlers()) {
+ if (!currentBlock.hasCatchHandlers()) {
// We found a NPE check on receiver.
return InstructionEffect.DESIRED_EFFECT;
}
@@ -1125,6 +1161,12 @@
});
}
+ private static boolean isNullabilityCheck(Instruction instr, Value receiver) {
+ return instr.isIf() && instr.asIf().isZeroTest()
+ && instr.inValues().get(0).equals(receiver)
+ && (instr.asIf().getType() == Type.EQ || instr.asIf().getType() == Type.NE);
+ }
+
private static boolean instructionHasSideEffects(Instruction instruction) {
// We consider that an instruction has side effects if it can throw an exception. This is a
// conservative approach which can be revised in the future.
@@ -1163,8 +1205,8 @@
*
* Note: we do not track phis so we may return false negative. This is a conservative approach.
*/
- private static boolean alwaysTriggerExpectedEffectBeforeAnythingElse(IRCode code,
- Function<Instruction, InstructionEffect> function) {
+ private static boolean alwaysTriggerExpectedEffectBeforeAnythingElse(
+ IRCode code, Function<Instruction, InstructionEffect> function) {
final int color = code.reserveMarkingColor();
try {
ArrayDeque<BasicBlock> worklist = new ArrayDeque<>();
@@ -1188,6 +1230,17 @@
// The current path is causing the expected effect. No need to go deeper in this path,
// go to the next block in the work list.
continue;
+ } else if (result == InstructionEffect.CONDITIONAL_EFFECT) {
+ assert !currentBlock.getNormalSuccessors().isEmpty();
+ Instruction lastInstruction = currentBlock.getInstructions().getLast();
+ assert lastInstruction.isIf();
+ // The current path is checking if the value of interest is null. Go deeper into the path
+ // that corresponds to the null value.
+ BasicBlock targetIfReceiverIsNull = lastInstruction.asIf().targetFromCondition(0);
+ if (!targetIfReceiverIsNull.isMarked(color)) {
+ worklist.add(targetIfReceiverIsNull);
+ targetIfReceiverIsNull.mark(color);
+ }
} else {
assert result == InstructionEffect.NO_EFFECT;
// The block did not cause any particular effect.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index ed92f64..0dacc69 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -66,7 +66,7 @@
@Override
public void finish() {
- if (Log.ENABLED) {
+ if (Log.ENABLED && info != null) {
Log.debug(getClass(), info.toString());
}
}
@@ -224,7 +224,7 @@
private int computeInstructionLimit(InvokeMethod invoke, DexEncodedMethod candidate) {
int instructionLimit = inliningInstructionLimit;
- BitSet hints = candidate.getOptimizationInfo().getKotlinNotNullParamHints();
+ BitSet hints = candidate.getOptimizationInfo().getNonNullParamHints();
if (hints != null) {
List<Value> arguments = invoke.inValues();
if (invoke.isInvokeMethodWithReceiver()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index ba2e77f..68eb269 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -217,8 +217,8 @@
this.strategyFactory = ApplyStrategy::new;
// Add synthesized lambda group classes to the builder.
+ converter.optimizeSynthesizedClasses(lambdaGroupsClasses.values(), executorService);
for (Entry<LambdaGroup, DexProgramClass> entry : lambdaGroupsClasses.entrySet()) {
- converter.optimizeSynthesizedClass(entry.getValue());
builder.addSynthesizedClass(entry.getValue(),
entry.getKey().shouldAddToMainDex(converter.appInfo));
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/DupDupDupPeephole.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/DupDupDupPeephole.java
index 9b86873..af41976 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/DupDupDupPeephole.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/DupDupDupPeephole.java
@@ -8,8 +8,6 @@
import com.android.tools.r8.ir.code.Dup2;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.StackValue;
-import com.android.tools.r8.ir.code.StackValues;
-import com.google.common.collect.ImmutableList;
/**
* Peephole that looks for the following pattern:
@@ -49,36 +47,28 @@
Dup dupMiddle = dup2Exp.get(match).asDup();
Dup dupBottom = dup1Exp.get(match).asDup();
- StackValue src = (StackValue) dupTop.inValues().get(0);
- StackValue srcMiddle = (StackValue) dupMiddle.inValues().get(0);
- StackValue srcBottom = (StackValue) dupBottom.inValues().get(0);
-
- StackValues tv = (StackValues) dupTop.outValue();
- StackValues mv = (StackValues) dupMiddle.outValue();
- StackValues bv = (StackValues) dupBottom.outValue();
-
// The stack looks like:
- // ..., tv0, mv0, bv0, bv1,.. -->
- // because tv1 was used by dupMiddle and mv1 was used by dupBottom.
+ // ..., dupTop0, dupMiddle0, dupBottom0, dupBottom1,.. -->
+ // because dupTop1 was used by dupMiddle and dupMiddle1 was used by dupBottom.
- StackValue tv0Dup2 = tv.getStackValues().get(0).duplicate(src.getHeight());
- StackValue mv0Dup2 = mv.getStackValues().get(0).duplicate(src.getHeight() + 1);
- StackValue bv0Dup2 = bv.getStackValues().get(0).duplicate(src.getHeight() + 2);
- StackValue bv1Dup2 = bv.getStackValues().get(1).duplicate(src.getHeight() + 3);
+ int height = dupTop.src().getHeight();
+
+ StackValue tv0Dup2 = dupTop.outBottom().duplicate(height);
+ StackValue mv0Dup2 = dupMiddle.outBottom().duplicate(height + 1);
+ StackValue bv0Dup2 = dupBottom.outBottom().duplicate(height + 2);
+ StackValue bv1Dup2 = dupBottom.outTop().duplicate(height + 3);
// Remove tv1 use.
- srcMiddle.removeUser(dupMiddle);
+ dupMiddle.src().removeUser(dupMiddle);
// Remove mv1 use.
- srcBottom.removeUser(dupBottom);
+ dupBottom.src().removeUser(dupBottom);
// Replace other uses.
- tv.getStackValues().get(0).replaceUsers(tv0Dup2);
- mv.getStackValues().get(0).replaceUsers(mv0Dup2);
- bv.getStackValues().get(0).replaceUsers(bv0Dup2);
- bv.getStackValues().get(1).replaceUsers(bv1Dup2);
+ dupTop.outBottom().replaceUsers(tv0Dup2);
+ dupMiddle.outBottom().replaceUsers(mv0Dup2);
+ dupBottom.outBottom().replaceUsers(bv0Dup2);
+ dupBottom.outTop().replaceUsers(bv1Dup2);
- StackValues dest = new StackValues(ImmutableList.of(tv0Dup2, mv0Dup2, bv0Dup2, bv1Dup2));
-
- Dup2 dup2 = new Dup2(dest, tv.getStackValues().get(0), tv.getStackValues().get(1));
+ Dup2 dup2 = new Dup2(tv0Dup2, mv0Dup2, bv0Dup2, bv1Dup2, dupTop.outBottom(), dupTop.outTop());
it.removeOrReplaceByDebugLocalRead();
it.previous();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/LoadLoadDupPeephole.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/LoadLoadDupPeephole.java
index eff527c..0914ee3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/LoadLoadDupPeephole.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/LoadLoadDupPeephole.java
@@ -9,8 +9,6 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Load;
import com.android.tools.r8.ir.code.StackValue;
-import com.android.tools.r8.ir.code.StackValues;
-import com.google.common.collect.ImmutableList;
/**
* {@link LoadLoadDupPeephole} looks for the following pattern:
@@ -59,12 +57,11 @@
int height = src.getHeight();
StackValue newFirstLoadOut = src.duplicate(height);
StackValue newLastLoadOut = src.duplicate(height + 1);
- StackValues dest = new StackValues(ImmutableList.of(newFirstLoadOut, newLastLoadOut));
firstLoad.outValue().replaceUsers(newFirstLoadOut);
lastLoad.outValue().replaceUsers(newLastLoadOut);
- it.replaceCurrentInstruction(new Dup(dest, src));
+ it.replaceCurrentInstruction(new Dup(newFirstLoadOut, newLastLoadOut, src));
return true;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/PeepholeHelper.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/PeepholeHelper.java
index 255e4bb..3747337 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/PeepholeHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/PeepholeHelper.java
@@ -50,7 +50,7 @@
return 1;
}
if (outValue instanceof StackValues) {
- return ((StackValues) outValue).getStackValues().size();
+ return ((StackValues) outValue).getStackValues().length;
}
return 0;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/StoreSequenceLoadPeephole.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/StoreSequenceLoadPeephole.java
index c2aead8..b1514ac 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/StoreSequenceLoadPeephole.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/StoreSequenceLoadPeephole.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.ir.code.StackValues;
import com.android.tools.r8.ir.code.Store;
import com.android.tools.r8.ir.code.Swap;
-import com.google.common.collect.ImmutableList;
import java.util.List;
/**
@@ -99,8 +98,8 @@
if (last.outValue() instanceof StackValue) {
lastOut = (StackValue) last.outValue();
} else if (last.outValue() instanceof StackValues) {
- List<StackValue> stackValues = ((StackValues) last.outValue()).getStackValues();
- lastOut = stackValues.get(stackValues.size() - 1);
+ StackValue[] stackValues = ((StackValues) last.outValue()).getStackValues();
+ lastOut = stackValues[stackValues.length - 1];
}
if (lastOut == null || lastOut.getTypeLattice().isWide()) {
@@ -115,19 +114,15 @@
// Remove the first store.
it.removeOrReplaceByDebugLocalRead();
- Instruction current = it.next();
- while (current != load) {
- current = it.next();
- }
+ it.nextUntil(i -> i == load);
// Insert a swap instruction
StackValue swapLastOut = lastOut.duplicate(source.getHeight());
StackValue swapSource = source.duplicate(swapLastOut.getHeight() + 1);
- StackValues dest = new StackValues(ImmutableList.of(swapLastOut, swapSource));
source.replaceUsers(swapSource);
lastOut.replaceUsers(swapLastOut);
- it.replaceCurrentInstruction(new Swap(dest, source, lastOut));
+ it.replaceCurrentInstruction(new Swap(swapLastOut, swapSource, source, lastOut));
PeepholeHelper.resetNext(it, 2);
return true;
}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index b3efe9d..aa89a3f 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.analysis.type;
import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.computeLeastUpperBoundOfInterfaces;
+import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.fromDexType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -452,6 +453,18 @@
}
@Test
+ public void testSelfOrderWithoutSubtypingInfo() {
+ DexType type = appInfo.dexItemFactory.createType("Lmy/Type;");
+ TypeLatticeElement nonNullType = fromDexType(type, false, appInfo);
+ TypeLatticeElement nullableType = nonNullType.asNullable();
+ // TODO(zerny): Once the null lattice is used for null info check that the class-type null is
+ // also more specific that the nullableType.
+ assertTrue(strictlyLessThan(nonNullType, nullableType));
+ assertTrue(lessThanOrEqual(nonNullType, nullableType));
+ assertFalse(lessThanOrEqual(nullableType, nonNullType));
+ }
+
+ @Test
public void testLeastUpperBoundOfInterfaces() {
DexType collection = factory.createType("Ljava/util/Collection;");
DexType set = factory.createType("Ljava/util/Set;");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index f7a4af6..d579b55 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -69,15 +69,15 @@
MethodSubject selfCheck = mainSubject.method("void", "selfCheck", ImmutableList.of());
assertThat(selfCheck, isPresent());
+ assertEquals(0, countCallToParamNullCheck(selfCheck));
assertEquals(1, countPrintCall(selfCheck));
assertEquals(0, countThrow(selfCheck));
MethodSubject checkNull = mainSubject.method("void", "checkNull", ImmutableList.of());
assertThat(checkNull, isPresent());
- // TODO(b/117848700): these can be checked iff checkParameterIsNotNull is inlined even after
- // the global inline threshold change.
- //assertEquals(0, countPrintCall(checkNull));
- //assertEquals(1, countThrow(checkNull));
+ assertEquals(1, countCallToParamNullCheck(checkNull));
+ assertEquals(1, countPrintCall(checkNull));
+ assertEquals(0, countThrow(checkNull));
String mainName = mainClass.getCanonicalName();
MethodSubject paramCheck =
@@ -114,6 +114,7 @@
MethodSubject checkViaIntrinsic =
mainSubject.method("void", "checkViaIntrinsic", ImmutableList.of(mainName));
assertThat(checkViaIntrinsic, isPresent());
+ assertEquals(0, countCallToParamNullCheck(checkViaIntrinsic));
// TODO(b/71500340): can be checked iff non-param info is propagated.
//assertEquals(1, countPrintCall(checkViaIntrinsic));
@@ -124,12 +125,20 @@
//assertEquals(1, countPrintCall(checkAtOneLevelHigher));
}
+ private long countCallToParamNullCheck(MethodSubject method) {
+ return countCall(method, IntrinsicsDeputy.class.getSimpleName(), "checkParameterIsNotNull");
+ }
+
private long countPrintCall(MethodSubject method) {
+ return countCall(method, "PrintStream", "print");
+ }
+
+ private long countCall(MethodSubject method, String className, String methodName) {
return Streams.stream(method.iterateInstructions(instructionSubject -> {
if (instructionSubject.isInvoke()) {
DexMethod invokedMethod = instructionSubject.getMethod();
- return invokedMethod.getHolder().toString().contains("PrintStream")
- && invokedMethod.name.toString().contains("print");
+ return invokedMethod.getHolder().toString().contains(className)
+ && invokedMethod.name.toString().contains(methodName);
}
return false;
})).count();