Merge commit 'edb9c27116bd338ec6c12064b2a5dbe8cea88308' into dev-release
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java index 501d4ae..e9dbc44 100644 --- a/src/main/java/com/android/tools/r8/D8Command.java +++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -393,7 +393,7 @@ assert !internal.debug; internal.debug = getMode() == CompilationMode.DEBUG; internal.programConsumer = getProgramConsumer(); - if (internal.programConsumer instanceof ClassFileConsumer) { + if (internal.isGeneratingClassFiles()) { internal.cfToCfDesugar = true; } internal.mainDexListConsumer = getMainDexListConsumer();
diff --git a/src/main/java/com/android/tools/r8/cf/CfVersion.java b/src/main/java/com/android/tools/r8/cf/CfVersion.java index f606b93..100656f 100644 --- a/src/main/java/com/android/tools/r8/cf/CfVersion.java +++ b/src/main/java/com/android/tools/r8/cf/CfVersion.java
@@ -5,8 +5,8 @@ import com.android.tools.r8.utils.structural.Equatable; import com.android.tools.r8.utils.structural.HashCodeVisitor; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import org.objectweb.asm.Opcodes; @@ -57,7 +57,7 @@ } @Override - public StructuralAccept<CfVersion> getStructuralAccept() { + public StructuralMapping<CfVersion> getStructuralMapping() { return CfVersion::specify; }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java index 7cfcf5b..e102cf7 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -52,9 +52,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } public Opcode getOpcode() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java index 44699bf..22421de 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java index a8d3546..c82e53e 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -42,9 +42,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } public MemberType getType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java index fa27c39..5d64188 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } private int getStoreType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java index b4b33b1..721f3f7 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - type.acceptCompareTo(((CfCheckCast) other).type, visitor); + return type.acceptCompareTo(((CfCheckCast) other).type, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java index d1d4bb9..9572e12 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -49,9 +49,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } public Bias getBias() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java index 7931528..863dce0 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -40,9 +40,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - type.acceptCompareTo(((CfConstClass) other).type, visitor); + return type.acceptCompareTo(((CfConstClass) other).type, visitor); } public DexType getType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java index 17c2abe..16f5e9a 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - handle.acceptCompareTo(((CfConstMethodHandle) other).handle, visitor); + return handle.acceptCompareTo(((CfConstMethodHandle) other).handle, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java index 85f125e..5bb9849 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - type.acceptCompareTo(((CfConstMethodType) other).type, visitor); + return type.acceptCompareTo(((CfConstMethodType) other).type, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java index 7575c49..185981e 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java index 23f3a2d..7484e80 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -21,6 +21,7 @@ import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.structural.CompareToVisitor; +import com.android.tools.r8.utils.structural.StructuralSpecification; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -29,6 +30,10 @@ private final long value; private final ValueType type; + private static void specify(StructuralSpecification<CfConstNumber, ?> spec) { + spec.withLong(CfConstNumber::getRawValue).withItem(CfConstNumber::getType); + } + public CfConstNumber(long value, ValueType type) { this.value = value; this.type = type; @@ -40,12 +45,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visit( - this, - (CfConstNumber) other, - spec -> spec.withLong(CfConstNumber::getRawValue).withItem(CfConstNumber::getType)); + return visitor.visit(this, (CfConstNumber) other, CfConstNumber::specify); } public ValueType getType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java index 827e77e..376edfe 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -36,9 +36,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - string.acceptCompareTo(other.asConstString().string, visitor); + return string.acceptCompareTo(other.asConstString().string, visitor); } public DexString getString() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java index e880a23..75c5eda 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -43,9 +43,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visitDexReference(item, ((CfDexItemBasedConstString) other).item); + return visitor.visitDexReference(item, ((CfDexItemBasedConstString) other).item); } public DexReference getItem() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java index 978a43d..6176b49 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -60,9 +60,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visit(this, other.asFieldInstruction(), CfFieldInstruction::specify); + return visitor.visit(this, other.asFieldInstruction(), CfFieldInstruction::specify); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java index d89ef90..713d764 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -153,11 +153,11 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { // The frame should be determined by the code so it should for equal iff the code is equal. // Thus we just require the frame to be in place. - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } private static class InitializedType extends FrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java index 7b3ccf8..2f4a549 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -36,9 +36,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - helper.compareLabels(target, ((CfGoto) other).target, visitor); + return helper.compareLabels(target, ((CfGoto) other).target, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java index 6e00da7..b331673 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -44,12 +44,12 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { CfIf otherIf = (CfIf) other; assert kind == otherIf.kind; assert type == otherIf.type; - helper.compareLabels(target, otherIf.target, visitor); + return helper.compareLabels(target, otherIf.target, visitor); } public ValueType getType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java index 35f9af3..45b426b 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -44,12 +44,12 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { CfIfCmp otherIf = (CfIfCmp) other; assert kind == otherIf.kind; assert type == otherIf.type; - helper.compareLabels(target, otherIf.target, visitor); + return helper.compareLabels(target, otherIf.target, visitor); } public Type getKind() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java index 04a7599..933dfcd 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -20,6 +20,7 @@ import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.structural.CompareToVisitor; +import com.android.tools.r8.utils.structural.StructuralSpecification; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -28,6 +29,10 @@ private final int var; private final int increment; + private static void specify(StructuralSpecification<CfIinc, ?> spec) { + spec.withInt(CfIinc::getLocalIndex).withInt(CfIinc::getIncrement); + } + public CfIinc(int var, int increment) { this.var = var; this.increment = increment; @@ -39,12 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visit( - this, - (CfIinc) other, - spec -> spec.withInt(CfIinc::getLocalIndex).withInt(CfIinc::getIncrement)); + return visitor.visit(this, (CfIinc) other, CfIinc::specify); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java index 4d311fe..815500d 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -49,9 +49,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - clazz.acceptCompareTo(((CfInitClass) other).clazz, visitor); + return clazz.acceptCompareTo(((CfInitClass) other).clazz, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java index 85d9b59..c18eb57 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -43,9 +43,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - type.acceptCompareTo(other.asInstanceOf().type, visitor); + return type.acceptCompareTo(other.asInstanceOf().type, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java index d4986b3..e7ae429 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -61,17 +61,16 @@ * <p>If an instruction is uniquely determined by the "compare id" then the override should simply * call '{@code CfCompareHelper::compareIdUniquelyDeterminesEquality}'. */ - public abstract void internalAcceptCompareTo( + public abstract int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper); - public final void acceptCompareTo( + public final int acceptCompareTo( CfInstruction o, CompareToVisitor visitor, CfCompareHelper helper) { - int diff = getCompareToId() - o.getCompareToId(); - if (diff == 0) { - internalAcceptCompareTo(o, visitor, helper); - } else { - visitor.visitInt(getCompareToId(), o.getCompareToId()); + int diff = visitor.visitInt(getCompareToId(), o.getCompareToId()); + if (diff != 0) { + return diff; } + return internalAcceptCompareTo(o, visitor, helper); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java index 4d1af96..07b0e0c 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -34,6 +34,7 @@ import com.android.tools.r8.ir.optimize.InliningConstraints; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.structural.CompareToVisitor; +import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.Arrays; import java.util.ListIterator; import org.objectweb.asm.MethodVisitor; @@ -45,6 +46,10 @@ private final int opcode; private final boolean itf; + private static void specify(StructuralSpecification<CfInvoke, ?> spec) { + spec.withBool(CfInvoke::isInterface).withItem(CfInvoke::getMethod); + } + public CfInvoke(int opcode, DexMethod method, boolean itf) { assert Opcodes.INVOKEVIRTUAL <= opcode && opcode <= Opcodes.INVOKEINTERFACE; assert !(opcode == Opcodes.INVOKEVIRTUAL && itf) : "InvokeVirtual on interface type"; @@ -60,13 +65,10 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { CfInvoke otherInvoke = other.asInvoke(); - visitor.visit( - this, - otherInvoke, - spec -> spec.withBool(CfInvoke::isInterface).withItem(CfInvoke::getMethod)); + return visitor.visit(this, otherInvoke, CfInvoke::specify); } public DexMethod getMethod() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java index fc1f3e5..e65d095 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -49,9 +49,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - callSite.acceptCompareTo(((CfInvokeDynamic) other).callSite, visitor); + return callSite.acceptCompareTo(((CfInvokeDynamic) other).callSite, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java index d8cd219..812a17c 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -42,7 +42,7 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { throw error(); }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java index dc6d863..5a3e4e7 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -39,9 +39,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - helper.compareLabels(this, other.asLabel(), visitor); + return helper.compareLabels(this, other.asLabel(), visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java index 4e48880..96a6d11 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -41,9 +41,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visitInt(var, other.asLoad().var); + return visitor.visitInt(var, other.asLoad().var); } private int getLoadType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java index d6264f7..19e5dd9 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -54,9 +54,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } public NumericType getType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java index 520c168..3286da2 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -43,9 +43,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java index ff9ea71..9180511 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -22,6 +22,7 @@ import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.structural.CompareToVisitor; +import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.ListIterator; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -31,6 +32,10 @@ private final DexType type; private final int dimensions; + private static void specify(StructuralSpecification<CfMultiANewArray, ?> spec) { + spec.withInt(CfMultiANewArray::getDimensions).withItem(CfMultiANewArray::getType); + } + public CfMultiANewArray(DexType type, int dimensions) { this.type = type; this.dimensions = dimensions; @@ -50,12 +55,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visit( - this, - (CfMultiANewArray) other, - spec -> spec.withInt(CfMultiANewArray::getDimensions).withItem(CfMultiANewArray::getType)); + return visitor.visit(this, (CfMultiANewArray) other, CfMultiANewArray::specify); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java index dce1028..5de3787 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java index 87a407d..7140404 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -44,9 +44,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - type.acceptCompareTo(((CfNew) other).type, visitor); + return type.acceptCompareTo(((CfNew) other).type, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java index 0dbf78e..bd36756 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -47,9 +47,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - type.acceptCompareTo(((CfNewArray) other).type, visitor); + return type.acceptCompareTo(((CfNewArray) other).type, visitor); } private int getPrimitiveTypeCode() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java index 0a69673b..974d928 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -30,9 +30,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java index 35c78a7..dc1bc2c 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -46,9 +46,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } public NumericType getFromType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java index df8612e..f524bab 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -27,6 +27,8 @@ private final CfLabel label; private final Position position; + + public CfPosition(CfLabel label, Position position) { this.label = label; this.position = position; @@ -38,9 +40,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visit( + return visitor.visit( this, (CfPosition) other, spec ->
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java index b09fbea..51d1283 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -43,9 +43,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } private int getOpcode() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java index c52efe3..08de455 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -35,9 +35,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java index c6c39be..bfdbe0a 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -88,9 +88,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java index e424474..d74eb39 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -42,9 +42,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visitInt(var, other.asStore().var); + return visitor.visitInt(var, other.asStore().var); } private int getStoreType() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java index 86abb2e..cb915ff 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -51,11 +51,10 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { assert kind == ((CfSwitch) other).kind; - - visitor.visit( + return visitor.visit( this, (CfSwitch) other, spec -> @@ -156,5 +155,6 @@ for (CfLabel target : targets) { frameBuilder.verifyTarget(target); } + frameBuilder.setNoFrame(); } }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java index 7243175..aad20a8 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -36,9 +36,9 @@ } @Override - public void internalAcceptCompareTo( + public int internalAcceptCompareTo( CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) { - CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); + return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java b/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java index 6cc3b13..2f821be 100644 --- a/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java +++ b/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java
@@ -48,8 +48,8 @@ return new CfTryCatch(start, end, guards, targets); } - public void acceptCompareTo(CfTryCatch other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visit( + public int acceptCompareTo(CfTryCatch other, CompareToVisitor visitor, CfCompareHelper helper) { + return visitor.visit( this, other, spec ->
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java index c07e0f5..6f2f904 100644 --- a/src/main/java/com/android/tools/r8/dex/FileWriter.java +++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -133,7 +133,7 @@ Log.verbose(FileWriter.class, "Writing encoded annotation @ %08x", dest.position()); } List<DexAnnotationElement> elements = new ArrayList<>(Arrays.asList(annotation.elements)); - elements.sort((a, b) -> a.name.compareToWithNamingLens(b.name, mapping.getNamingLens())); + elements.sort((a, b) -> a.name.acceptCompareTo(b.name, mapping.getCompareToVisitor())); dest.putUleb128(mapping.getOffsetFor(annotation.type)); dest.putUleb128(elements.size()); for (DexAnnotationElement element : elements) { @@ -351,6 +351,7 @@ } private static String getKeyForDexCodeSorting(ProgramMethod method, ClassNameMapper proguardMap) { + // TODO(b/173999869): Could this instead compute sorting using dex items? Signature signature; String originalClassName; if (proguardMap != null) { @@ -580,7 +581,8 @@ } List<DexAnnotation> annotations = new ArrayList<>(Arrays.asList(set.annotations)); annotations.sort( - (a, b) -> a.annotation.type.compareToWithNamingLens(b.annotation.type, namingLens)); + (a, b) -> + a.annotation.type.acceptCompareTo(b.annotation.type, mapping.getCompareToVisitor())); dest.putInt(annotations.size()); for (DexAnnotation annotation : annotations) { dest.putInt(mixedSectionOffsets.getOffsetFor(annotation)); @@ -613,10 +615,11 @@ mixedSectionOffsets.setOffsetForAnnotationsDirectory(annotationDirectory, dest.align(4)); dest.putInt(mixedSectionOffsets.getOffsetFor(annotationDirectory.getClazzAnnotations())); List<DexEncodedMethod> methodAnnotations = - annotationDirectory.sortMethodAnnotations(namingLens); + annotationDirectory.sortMethodAnnotations(mapping.getCompareToVisitor()); List<DexEncodedMethod> parameterAnnotations = - annotationDirectory.sortParameterAnnotations(namingLens); - List<DexEncodedField> fieldAnnotations = annotationDirectory.sortFieldAnnotations(namingLens); + annotationDirectory.sortParameterAnnotations(mapping.getCompareToVisitor()); + List<DexEncodedField> fieldAnnotations = + annotationDirectory.sortFieldAnnotations(mapping.getCompareToVisitor()); dest.putInt(fieldAnnotations.size()); dest.putInt(methodAnnotations.size()); dest.putInt(parameterAnnotations.size()); @@ -630,7 +633,7 @@ private void writeEncodedFields(List<DexEncodedField> unsortedFields) { List<DexEncodedField> fields = new ArrayList<>(unsortedFields); - fields.sort((a, b) -> a.field.compareToWithNamingLens(b.field, namingLens)); + fields.sort((a, b) -> a.field.acceptCompareTo(b.field, mapping.getCompareToVisitor())); int currentOffset = 0; for (DexEncodedField field : fields) { assert field.validateDexValue(application.dexItemFactory); @@ -646,7 +649,7 @@ private void writeEncodedMethods( Iterable<DexEncodedMethod> unsortedMethods, boolean isSharedSynthetic) { List<DexEncodedMethod> methods = IterableUtils.toNewArrayList(unsortedMethods); - methods.sort((a, b) -> a.method.compareToWithNamingLens(b.method, namingLens)); + methods.sort((a, b) -> a.method.acceptCompareTo(b.method, mapping.getCompareToVisitor())); int currentOffset = 0; for (DexEncodedMethod method : methods) { int nextOffset = mapping.getOffsetFor(method.method);
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java index 910153a..e47b428 100644 --- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java +++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.graph; import com.android.tools.r8.dex.Constants; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import com.google.common.collect.ImmutableList; import java.util.List; @@ -61,7 +61,7 @@ } @Override - public StructuralAccept<T> getStructuralAccept() { + public StructuralMapping<T> getStructuralMapping() { return AccessFlags::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java index 1e7ec9c..ce2d937 100644 --- a/src/main/java/com/android/tools/r8/graph/AppView.java +++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -9,7 +9,6 @@ import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens; import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis.InitializedClassesInInstanceMethods; import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses; -import com.android.tools.r8.graph.classmerging.MergedClasses; import com.android.tools.r8.graph.classmerging.MergedClassesCollection; import com.android.tools.r8.graph.classmerging.StaticallyMergedClasses; import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses; @@ -455,12 +454,6 @@ return collection; } - public boolean hasBeenMerged(DexProgramClass clazz) { - return MergedClasses.hasBeenMerged(horizontallyMergedClasses, clazz) - || MergedClasses.hasBeenMerged(horizontallyMergedLambdaClasses, clazz) - || MergedClasses.hasBeenMerged(verticallyMergedClasses, clazz); - } - /** * Get the result of horizontal lambda class merging. Returns null if horizontal lambda class * merging has not been run. @@ -636,7 +629,7 @@ boolean changed = appView.setGraphLens(lens); assert changed; - assert application.verifyWithLens(lens); + assert application.verifyWithLens(appView.appInfo().app().asDirect(), lens); // The application has already been rewritten with the given applied lens. Therefore, we // temporarily replace that lens with a lens that does not have any rewritings to avoid the
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java index 6d3cedc..2e1eeb6 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCode.java +++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -43,8 +43,8 @@ import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.structural.CompareToVisitor; import com.android.tools.r8.utils.structural.HashingVisitor; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.google.common.base.Strings; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap; @@ -112,9 +112,9 @@ return end; } - public void acceptCompareTo( + public int acceptCompareTo( LocalVariableInfo other, CompareToVisitor visitor, CfCompareHelper helper) { - visitor.visit( + return visitor.visit( this, other, spec -> @@ -164,7 +164,7 @@ } @Override - public StructuralAccept<CfCode> getStructuralAccept() { + public StructuralMapping<CfCode> getStructuralMapping() { throw new Unreachable(); } @@ -254,9 +254,9 @@ } @Override - public void acceptCompareTo(CfCode other, CompareToVisitor visitor) { + public int acceptCompareTo(CfCode other, CompareToVisitor visitor) { CfCompareHelper helper = new CfCompareHelper(this, other); - visitor.visit( + return visitor.visit( this, other, spec -> @@ -695,7 +695,7 @@ public boolean verifyFrames( DexEncodedMethod method, AppView<?> appView, Origin origin, boolean applyProtoTypeChanges) { - if (!appView.options().testing.readInputStackMaps + if (!appView.options().canUseInputStackMaps() || appView.options().testing.disableStackMapVerification) { stackMapStatus = StackMapStatus.INVALID_OR_NOT_PRESENT; return true;
diff --git a/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java b/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java index 0203b0c..1108c72 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java +++ b/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java
@@ -45,11 +45,12 @@ } // Helper to signal that the concrete instruction is uniquely determined by its ID/opcode. - public static void compareIdUniquelyDeterminesEquality( + public static int compareIdUniquelyDeterminesEquality( CfInstruction instruction1, CfInstruction instruction2) { assert instruction1.getClass() == instruction2.getClass(); assert instruction1.getCompareToId() == instruction2.getCompareToId(); assert instruction1.toString().equals(instruction2.toString()); + return 0; } private static Reference2IntMap<CfLabel> getLabelOrdering(CfCode code) { @@ -71,8 +72,8 @@ this.code2 = code2; } - public void compareLabels(CfLabel label1, CfLabel label2, CompareToVisitor visitor) { - labelAcceptor().acceptCompareTo(label1, label2, visitor); + public int compareLabels(CfLabel label1, CfLabel label2, CompareToVisitor visitor) { + return labelAcceptor().acceptCompareTo(label1, label2, visitor); } public StructuralAcceptor<CfLabel> labelAcceptor() { @@ -83,8 +84,8 @@ private final Reference2IntMap<CfLabel> labels2 = getLabelOrdering(code2); @Override - public void acceptCompareTo(CfLabel item1, CfLabel item2, CompareToVisitor visitor) { - visitor.visitInt(labels1.getInt(item1), labels2.getInt(item2)); + public int acceptCompareTo(CfLabel item1, CfLabel item2, CompareToVisitor visitor) { + return visitor.visitInt(labels1.getInt(item1), labels2.getInt(item2)); } @Override @@ -100,9 +101,9 @@ CfCompareHelper helper = this; return new StructuralAcceptor<CfInstruction>() { @Override - public void acceptCompareTo( + public int acceptCompareTo( CfInstruction item1, CfInstruction item2, CompareToVisitor visitor) { - item1.acceptCompareTo(item2, visitor, helper); + return item1.acceptCompareTo(item2, visitor, helper); } @Override @@ -116,8 +117,8 @@ CfCompareHelper helper = this; return new StructuralAcceptor<CfTryCatch>() { @Override - public void acceptCompareTo(CfTryCatch item1, CfTryCatch item2, CompareToVisitor visitor) { - item1.acceptCompareTo(item2, visitor, helper); + public int acceptCompareTo(CfTryCatch item1, CfTryCatch item2, CompareToVisitor visitor) { + return item1.acceptCompareTo(item2, visitor, helper); } @Override @@ -131,9 +132,9 @@ CfCompareHelper helper = this; return new StructuralAcceptor<LocalVariableInfo>() { @Override - public void acceptCompareTo( + public int acceptCompareTo( LocalVariableInfo item1, LocalVariableInfo item2, CompareToVisitor visitor) { - item1.acceptCompareTo(item2, visitor, helper); + return item1.acceptCompareTo(item2, visitor, helper); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DebugLocalInfo.java b/src/main/java/com/android/tools/r8/graph/DebugLocalInfo.java index 56027f2..67a8eab 100644 --- a/src/main/java/com/android/tools/r8/graph/DebugLocalInfo.java +++ b/src/main/java/com/android/tools/r8/graph/DebugLocalInfo.java
@@ -5,8 +5,8 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.utils.DescriptorUtils; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; @@ -45,7 +45,7 @@ } @Override - public StructuralAccept<DebugLocalInfo> getStructuralAccept() { + public StructuralMapping<DebugLocalInfo> getStructuralMapping() { return DebugLocalInfo::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java index 5f223f8..bcb7974 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -16,8 +16,8 @@ import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.Pair; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.ArrayList; import java.util.Collection; @@ -35,7 +35,7 @@ public final DexEncodedAnnotation annotation; private static void specify(StructuralSpecification<DexAnnotation, ?> spec) { - spec.withInt(a -> a.visibility).withItem(a -> a.annotation); + spec.withItem(a -> a.annotation).withInt(a -> a.visibility); } public DexAnnotation(int visibility, DexEncodedAnnotation annotation) { @@ -49,7 +49,7 @@ } @Override - public StructuralAccept<DexAnnotation> getStructuralAccept() { + public StructuralMapping<DexAnnotation> getStructuralMapping() { return DexAnnotation::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java index 2ee613c..ad9bf23 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.naming.NamingLens; +import com.android.tools.r8.utils.structural.CompareToVisitor; import java.util.ArrayList; import java.util.List; @@ -45,18 +45,18 @@ return clazz.annotations(); } - public List<DexEncodedMethod> sortMethodAnnotations(NamingLens namingLens) { - methodAnnotations.sort((a, b) -> a.method.compareToWithNamingLens(b.method, namingLens)); + public List<DexEncodedMethod> sortMethodAnnotations(CompareToVisitor visitor) { + methodAnnotations.sort((a, b) -> a.method.acceptCompareTo(b.method, visitor)); return methodAnnotations; } - public List<DexEncodedMethod> sortParameterAnnotations(NamingLens namingLens) { - parameterAnnotations.sort((a, b) -> a.method.compareToWithNamingLens(b.method, namingLens)); + public List<DexEncodedMethod> sortParameterAnnotations(CompareToVisitor visitor) { + parameterAnnotations.sort((a, b) -> a.method.acceptCompareTo(b.method, visitor)); return parameterAnnotations; } - public List<DexEncodedField> sortFieldAnnotations(NamingLens namingLens) { - fieldAnnotations.sort((a, b) -> a.field.compareToWithNamingLens(b.field, namingLens)); + public List<DexEncodedField> sortFieldAnnotations(CompareToVisitor visitor) { + fieldAnnotations.sort((a, b) -> a.field.acceptCompareTo(b.field, visitor)); return fieldAnnotations; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java index fc764ff..f351642 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -5,8 +5,8 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; public class DexAnnotationElement extends DexItem implements StructuralItem<DexAnnotationElement> { @@ -30,7 +30,7 @@ } @Override - public StructuralAccept<DexAnnotationElement> getStructuralAccept() { + public StructuralMapping<DexAnnotationElement> getStructuralMapping() { return DexAnnotationElement::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java index 86188d6..e1a64b1 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -9,8 +9,8 @@ import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.ArrayUtils; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import com.google.common.collect.Sets; import java.util.Arrays; @@ -47,7 +47,7 @@ } @Override - public StructuralAccept<DexAnnotationSet> getStructuralAccept() { + public StructuralMapping<DexAnnotationSet> getStructuralMapping() { return DexAnnotationSet::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java index 5d521bc..9cb4704 100644 --- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java +++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -10,8 +10,8 @@ import com.android.tools.r8.graph.DexValue.DexValueMethodHandle; import com.android.tools.r8.graph.DexValue.DexValueMethodType; import com.android.tools.r8.graph.DexValue.DexValueString; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import com.google.common.io.BaseEncoding; import java.io.ByteArrayOutputStream; @@ -108,7 +108,7 @@ } @Override - public StructuralAccept<DexCallSite> getStructuralAccept() { + public StructuralMapping<DexCallSite> getStructuralMapping() { return DexCallSite::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinition.java b/src/main/java/com/android/tools/r8/graph/DexDefinition.java index 0153cd2..c3e6998 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDefinition.java +++ b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
@@ -104,4 +104,16 @@ public abstract boolean isStatic(); public abstract boolean isStaticMember(); + + public boolean isNotProgramDefinition(AppView<?> appView) { + if (isDexClass()) { + return asDexClass().isNotProgramClass(); + } + DexClass clazz = appView.definitionFor(asDexEncodedMember().getHolderType()); + return clazz == null || clazz.isNotProgramClass(); + } + + public DexType getContextType() { + return isDexClass() ? asDexClass().type : asDexEncodedMember().getHolderType(); + } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java index bcefcd2..98df8c7 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -6,8 +6,8 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.utils.ArrayUtils; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.Arrays; import java.util.function.Consumer; @@ -37,7 +37,7 @@ } @Override - public StructuralAccept<DexEncodedAnnotation> getStructuralAccept() { + public StructuralMapping<DexEncodedAnnotation> getStructuralMapping() { return DexEncodedAnnotation::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java index 133ebe5..6839371 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -20,8 +20,8 @@ import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo; import com.android.tools.r8.kotlin.KotlinFieldLevelInfo; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; public class DexEncodedField extends DexEncodedMember<DexEncodedField, DexField> @@ -75,7 +75,7 @@ } @Override - public StructuralAccept<DexEncodedField> getStructuralAccept() { + public StructuralMapping<DexEncodedField> getStructuralMapping() { return DexEncodedField::specify; }
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 6fbb596..7d807e9 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -358,18 +358,15 @@ this, other, map, DexEncodedMethod::syntheticSpecify); } - private static void compareCodeObject(Code code1, Code code2, CompareToVisitor visitor) { + private static int compareCodeObject(Code code1, Code code2, CompareToVisitor visitor) { if (code1.isCfCode() && code2.isCfCode()) { - code1.asCfCode().acceptCompareTo(code2.asCfCode(), visitor); - } else if (code1.isDexCode() && code2.isDexCode()) { - visitor.visit(code1.asDexCode(), code2.asDexCode(), DexCode::compareTo); - } else { - throw new Unreachable( - "Unexpected attempt to compare incompatible synthetic objects: " - + code1 - + " and " - + code2); + return code1.asCfCode().acceptCompareTo(code2.asCfCode(), visitor); } + if (code1.isDexCode() && code2.isDexCode()) { + return visitor.visit(code1.asDexCode(), code2.asDexCode(), DexCode::compareTo); + } + throw new Unreachable( + "Unexpected attempt to compare incompatible synthetic objects: " + code1 + " and " + code2); } private static void hashCodeObject(Code code, HashingVisitor visitor) { @@ -846,6 +843,12 @@ classFileVersion = Ordered.maxIgnoreNull(classFileVersion, version); } + public void downgradeClassFileVersion(CfVersion version) { + checkIfObsolete(); + assert version != null; + classFileVersion = Ordered.minIgnoreNull(classFileVersion, version); + } + public String qualifiedName() { checkIfObsolete(); return method.qualifiedName();
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java index dbb2d08..70bb89b 100644 --- a/src/main/java/com/android/tools/r8/graph/DexField.java +++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.references.FieldReference; import com.android.tools.r8.references.Reference; import com.android.tools.r8.utils.structural.CompareToVisitor; -import com.android.tools.r8.utils.structural.StructuralAccept; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.Collections; import java.util.function.BiConsumer; @@ -28,7 +28,7 @@ } } - private static void accept(StructuralSpecification<DexField, ?> spec) { + private static void specify(StructuralSpecification<DexField, ?> spec) { spec.withItem(DexField::getHolderType).withItem(DexField::getName).withItem(DexField::getType); } @@ -38,8 +38,8 @@ } @Override - public StructuralAccept<DexField> getStructuralAccept() { - return DexField::accept; + public StructuralMapping<DexField> getStructuralMapping() { + return DexField::specify; } public DexType getType() { @@ -134,8 +134,8 @@ } @Override - public void acceptCompareTo(DexField other, CompareToVisitor visitor) { - visitor.visitDexField(this, other); + public int acceptCompareTo(DexField other, CompareToVisitor visitor) { + return visitor.visitDexField(this, other); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java index 97f9b6d..c91ffdf 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.references.Reference; import com.android.tools.r8.references.TypeReference; import com.android.tools.r8.utils.structural.CompareToVisitor; -import com.android.tools.r8.utils.structural.StructuralAccept; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.ArrayList; import java.util.List; @@ -31,13 +31,13 @@ } } - private static void accept(StructuralSpecification<DexMethod, ?> spec) { + private static void specify(StructuralSpecification<DexMethod, ?> spec) { spec.withItem(DexMethod::getHolderType).withItem(DexMethod::getName).withItem(m -> m.proto); } @Override - public StructuralAccept<DexMethod> getStructuralAccept() { - return DexMethod::accept; + public StructuralMapping<DexMethod> getStructuralMapping() { + return DexMethod::specify; } @Override @@ -46,8 +46,8 @@ } @Override - public void acceptCompareTo(DexMethod other, CompareToVisitor visitor) { - visitor.visitDexMethod(this, other); + public int acceptCompareTo(DexMethod other, CompareToVisitor visitor) { + return visitor.visitDexMethod(this, other); } public DexType getParameter(int index) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java index 5ee9c8f..b369871 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -8,7 +8,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.ir.code.Invoke.Type; import com.android.tools.r8.naming.NamingLens; -import com.android.tools.r8.utils.structural.StructuralAccept; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.Objects; import org.objectweb.asm.Handle; @@ -320,7 +320,7 @@ } @Override - public StructuralAccept<DexMethodHandle> getStructuralAccept() { + public StructuralMapping<DexMethodHandle> getStructuralMapping() { return DexMethodHandle::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java index ee32f8a..3e92e74 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -20,6 +20,7 @@ import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.TraversalContinuation; +import com.android.tools.r8.utils.structural.Ordered; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.util.ArrayList; @@ -669,12 +670,16 @@ this.initialClassFileVersion = initialClassFileVersion; } + public void downgradeInitialClassFileVersion(CfVersion version) { + assert version != null; + this.initialClassFileVersion = Ordered.minIgnoreNull(this.initialClassFileVersion, version); + } + public boolean hasClassFileVersion() { return initialClassFileVersion != null; } public CfVersion getInitialClassFileVersion() { - assert initialClassFileVersion != null; return initialClassFileVersion; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java index 3855408..36ad355 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProto.java +++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -5,7 +5,7 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.naming.NamingLens; -import com.android.tools.r8.utils.structural.StructuralAccept; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import com.google.common.collect.Iterables; import java.util.Collections; @@ -25,7 +25,7 @@ this.parameters = parameters; } - private static void accept(StructuralSpecification<DexProto, ?> spec) { + private static void specify(StructuralSpecification<DexProto, ?> spec) { spec.withItem(DexProto::getReturnType) .withItem(p -> p.parameters) // TODO(b/172206529): Consider removing shorty. @@ -33,8 +33,8 @@ } @Override - public StructuralAccept<DexProto> getStructuralAccept() { - return DexProto::accept; + public StructuralMapping<DexProto> getStructuralMapping() { + return DexProto::specify; } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java index 264a7aa..031ee9d 100644 --- a/src/main/java/com/android/tools/r8/graph/DexString.java +++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -12,7 +12,7 @@ import com.android.tools.r8.utils.ThrowingCharIterator; import com.android.tools.r8.utils.structural.CompareToVisitor; import com.android.tools.r8.utils.structural.HashingVisitor; -import com.android.tools.r8.utils.structural.StructuralAccept; +import com.android.tools.r8.utils.structural.StructuralMapping; import java.io.UTFDataFormatException; import java.util.Arrays; import java.util.NoSuchElementException; @@ -41,7 +41,7 @@ } @Override - public StructuralAccept<DexString> getStructuralAccept() { + public StructuralMapping<DexString> getStructuralMapping() { // Structural accept is never accessed as all accept methods are defined directly. throw new Unreachable(); } @@ -53,8 +53,8 @@ } @Override - public void acceptCompareTo(DexString other, CompareToVisitor visitor) { - visitor.visitDexString(this, other); + public int acceptCompareTo(DexString other, CompareToVisitor visitor) { + return visitor.visitDexString(this, other); } @Override
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 0b13d80..249439c 100644 --- a/src/main/java/com/android/tools/r8/graph/DexType.java +++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -26,7 +26,7 @@ import com.android.tools.r8.utils.InternalOptions.OutlineOptions; import com.android.tools.r8.utils.structural.CompareToVisitor; import com.android.tools.r8.utils.structural.HashingVisitor; -import com.android.tools.r8.utils.structural.StructuralAccept; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.google.common.collect.ImmutableList; import java.util.Arrays; import java.util.List; @@ -58,15 +58,15 @@ } @Override - public StructuralAccept<DexType> getStructuralAccept() { + public StructuralMapping<DexType> getStructuralMapping() { // Structural accept is never accessed as all accept methods are defined directly. throw new Unreachable(); } // DexType overrides accept to ensure the visitors always gets a visitDexType callback. @Override - public void acceptCompareTo(DexType other, CompareToVisitor visitor) { - visitor.visitDexType(this, other); + public int acceptCompareTo(DexType other, CompareToVisitor visitor) { + return visitor.visitDexType(this, other); } // DexType overrides accept to ensure the visitors always gets a visitDexType callback.
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java index 595c5dd..076322a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java +++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -8,8 +8,8 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.utils.ArrayUtils; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import com.google.common.collect.Iterators; import java.util.Arrays; @@ -72,7 +72,7 @@ } @Override - public StructuralAccept<DexTypeList> getStructuralAccept() { + public StructuralMapping<DexTypeList> getStructuralMapping() { return DexTypeList::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java index a54daf8..97d304b 100644 --- a/src/main/java/com/android/tools/r8/graph/DexValue.java +++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -25,8 +25,8 @@ import com.android.tools.r8.utils.EncodedValueUtils; import com.android.tools.r8.utils.structural.CompareToVisitor; import com.android.tools.r8.utils.structural.HashingVisitor; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import java.util.Arrays; import java.util.function.Consumer; import org.objectweb.asm.Handle; @@ -114,7 +114,7 @@ } @Override - public final StructuralAccept<DexValue> getStructuralAccept() { + public final StructuralMapping<DexValue> getStructuralMapping() { // DexValue is not generic at its base type (and can't as we use it as a polymorphic value), // so each concrete value must implement polymorphic accept functions. This base class // implements (most of) the polymorphic checks and concrete types implement the internal @@ -123,12 +123,12 @@ } @Override - public final void acceptCompareTo(DexValue other, CompareToVisitor visitor) { + public final int acceptCompareTo(DexValue other, CompareToVisitor visitor) { // Order first on 'kind', only equal kinds then forward to the 'kind' specific internal compare. if (getValueKind() != other.getValueKind()) { - visitor.visitInt(getValueKind().toByte(), other.getValueKind().toByte()); + return visitor.visitInt(getValueKind().toByte(), other.getValueKind().toByte()); } else { - internalAcceptCompareTo(other, visitor); + return internalAcceptCompareTo(other, visitor); } } @@ -139,7 +139,7 @@ internalAcceptHashing(visitor); } - abstract void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor); + abstract int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor); abstract void internalAcceptHashing(HashingVisitor visitor); @@ -478,8 +478,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitInt(value, other.asDexValueByte().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitInt(value, other.asDexValueByte().value); } @Override @@ -576,8 +576,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitInt(value, other.asDexValueShort().getValue()); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitInt(value, other.asDexValueShort().getValue()); } public short getValue() { @@ -663,8 +663,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitInt(value, other.asDexValueChar().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitInt(value, other.asDexValueChar().value); } @Override @@ -764,8 +764,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitInt(value, other.asDexValueInt().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitInt(value, other.asDexValueInt().value); } public int getValue() { @@ -851,8 +851,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitLong(value, other.asDexValueLong().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitLong(value, other.asDexValueLong().value); } @Override @@ -948,8 +948,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitFloat(value, other.asDexValueFloat().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitFloat(value, other.asDexValueFloat().value); } public float getValue() { @@ -1041,8 +1041,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitDouble(value, other.asDexValueDouble().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitDouble(value, other.asDexValueDouble().value); } @Override @@ -1201,10 +1201,12 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - if (DexItemBasedValueString.compareAndCheckValueStrings(this, other, visitor)) { - value.acceptCompareTo(other.asDexValueString().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + int order = DexItemBasedValueString.compareAndCheckValueStrings(this, other, visitor); + if (order != 0) { + return order; } + return value.acceptCompareTo(other.asDexValueString().value, visitor); } @Override @@ -1266,16 +1268,12 @@ // Helper to ensure a consistent order on DexValueString and DexItemBasedValueString which are // both defined to have kind 'string'. - static boolean compareAndCheckValueStrings(DexValue v1, DexValue v2, CompareToVisitor visitor) { + static int compareAndCheckValueStrings(DexValue v1, DexValue v2, CompareToVisitor visitor) { assert v1.getValueKind() == DexValueKind.STRING; assert v2.getValueKind() == DexValueKind.STRING; int order1 = v1.isDexItemBasedValueString() ? 1 : 0; int order2 = v2.isDexItemBasedValueString() ? 1 : 0; - boolean equal = order1 == order2; - if (!equal) { - visitor.visitInt(order1, order2); - } - return equal; + return visitor.visitInt(order1, order2); } private final NameComputationInfo<?> nameComputationInfo; @@ -1291,10 +1289,12 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - if (compareAndCheckValueStrings(this, other, visitor)) { - visitor.visitDexReference(value, other.asDexItemBasedValueString().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + int order = compareAndCheckValueStrings(this, other, visitor); + if (order != 0) { + return order; } + return visitor.visitDexReference(value, other.asDexItemBasedValueString().value); } @Override @@ -1368,8 +1368,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - value.acceptCompareTo(other.asDexValueType().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return value.acceptCompareTo(other.asDexValueType().value, visitor); } @Override @@ -1410,8 +1410,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - value.acceptCompareTo(other.asDexValueField().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return value.acceptCompareTo(other.asDexValueField().value, visitor); } @Override @@ -1452,8 +1452,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - value.acceptCompareTo(other.asDexValueMethod().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return value.acceptCompareTo(other.asDexValueMethod().value, visitor); } @Override @@ -1494,8 +1494,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - value.acceptCompareTo(other.asDexValueEnum().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return value.acceptCompareTo(other.asDexValueEnum().value, visitor); } @Override @@ -1536,8 +1536,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - value.acceptCompareTo(other.asDexValueMethodType().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return value.acceptCompareTo(other.asDexValueMethodType().value, visitor); } @Override @@ -1580,8 +1580,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitItemArray(values, other.asDexValueArray().values); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitItemArray(values, other.asDexValueArray().values); } @Override @@ -1689,8 +1689,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - value.acceptCompareTo(other.asDexValueAnnotation().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return value.acceptCompareTo(other.asDexValueAnnotation().value, visitor); } @Override @@ -1790,9 +1790,10 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { assert this == NULL; assert other == NULL; + return 0; } public Object getValue() { @@ -1882,8 +1883,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - visitor.visitBool(value, other.asDexValueBoolean().value); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return visitor.visitBool(value, other.asDexValueBoolean().value); } @Override @@ -1967,8 +1968,8 @@ } @Override - void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { - value.acceptCompareTo(other.asDexValueMethodHandle().value, visitor); + int internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) { + return value.acceptCompareTo(other.asDexValueMethodHandle().value, visitor); } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java index 54d6795..5a7d18f 100644 --- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java +++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -108,8 +108,8 @@ return "DexApplication (direct)"; } - public boolean verifyWithLens(GraphLens lens) { - assert mappingIsValid(lens, allClasses.keySet()); + public boolean verifyWithLens(DirectMappedDexApplication beforeLensApplication, GraphLens lens) { + assert mappingIsValid(beforeLensApplication.programClasses(), lens); assert verifyCodeObjectsOwners(); return true; } @@ -119,18 +119,22 @@ .allMatch( type -> lens.lookupType(type) == type - || MergedClasses.hasBeenMerged(appView.verticallyMergedClasses(), type) - || MergedClasses.hasBeenMerged(appView.horizontallyMergedClasses(), type)); + || MergedClasses.hasBeenMergedIntoDifferentType( + appView.verticallyMergedClasses(), type) + || MergedClasses.hasBeenMergedIntoDifferentType( + appView.horizontallyMergedClasses(), type)); assert verifyCodeObjectsOwners(); return true; } - private boolean mappingIsValid(GraphLens graphLens, Iterable<DexType> types) { + private boolean mappingIsValid( + List<DexProgramClass> classesBeforeLensApplication, GraphLens lens) { // The lens might either map to a different type that is already present in the application // (e.g. relinking a type) or it might encode a type that was renamed, in which case the // original type will point to a definition that was renamed. - for (DexType type : types) { - DexType renamed = graphLens.lookupType(type); + for (DexProgramClass clazz : classesBeforeLensApplication) { + DexType type = clazz.getType(); + DexType renamed = lens.lookupType(type); if (renamed.isIntType()) { continue; }
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java index cdafe4e..6a70cdd 100644 --- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java +++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -998,7 +998,7 @@ JarApplicationReader application, boolean reachabilitySensitive) { // TODO(b/166841731): We should compute our own from the compressed format. int parsingOptions = - application.options.testing.readInputStackMaps + application.options.canUseInputStackMaps() ? ClassReader.EXPAND_FRAMES : ClassReader.SKIP_FRAMES; ProguardConfiguration configuration = application.options.getProguardConfiguration();
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java index 61d9439..f315247 100644 --- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java +++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -8,8 +8,10 @@ import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils; import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.utils.Timing; +import com.android.tools.r8.utils.structural.CompareToVisitor; import com.android.tools.r8.utils.structural.CompareToVisitorWithStringTable; import com.android.tools.r8.utils.structural.CompareToVisitorWithTypeTable; +import com.android.tools.r8.utils.structural.StructuralItem; import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import it.unimi.dsi.fastutil.objects.Reference2IntMap.Entry; @@ -20,7 +22,6 @@ import java.util.Comparator; import java.util.List; import java.util.function.Consumer; -import java.util.function.ToIntFunction; import java.util.stream.Collectors; public class ObjectToOffsetMapping { @@ -45,6 +46,8 @@ private DexString firstJumboString; + private final CompareToVisitor compareToVisitor; + public ObjectToOffsetMapping( AppView<?> appView, GraphLens graphLens, @@ -76,40 +79,56 @@ this.lensCodeRewriter = new LensCodeRewriterUtils(appView); timing.begin("Sort strings"); this.strings = createSortedMap(strings, DexString::compareTo, this::setFirstJumboString); + CompareToVisitor visitor = + new CompareToVisitorWithStringTable(namingLens, this.strings::getInt); timing.end(); timing.begin("Sort types"); - this.types = createSortedMap(types, compareWithStringTable(), this::failOnOverflow); + this.types = createSortedMap(types, compare(visitor), this::failOnOverflow); + visitor = + new CompareToVisitorWithTypeTable(namingLens, this.strings::getInt, this.types::getInt); timing.end(); timing.begin("Sort classes"); this.classes = sortClasses(appView.appInfo(), classes, namingLens); timing.end(); timing.begin("Sort protos"); - this.protos = createSortedMap(protos, compareWithTypeTable(), this::failOnOverflow); + this.protos = createSortedMap(protos, compare(visitor), this::failOnOverflow); timing.end(); timing.begin("Sort methods"); - this.methods = createSortedMap(methods, compareWithTypeTable(), this::failOnOverflow); + this.methods = createSortedMap(methods, compare(visitor), this::failOnOverflow); timing.end(); timing.begin("Sort fields"); - this.fields = createSortedMap(fields, compareWithTypeTable(), this::failOnOverflow); + this.fields = createSortedMap(fields, compare(visitor), this::failOnOverflow); timing.end(); timing.begin("Sort call-sites"); - this.callSites = createSortedMap(callSites, DexCallSite::compareTo, this::failOnOverflow); + this.callSites = createSortedMap(callSites, compare(visitor), this::failOnOverflow); timing.end(); timing.begin("Sort method handles"); - this.methodHandles = - createSortedMap(methodHandles, compareWithTypeTable(), this::failOnOverflow); + this.methodHandles = createSortedMap(methodHandles, compare(visitor), this::failOnOverflow); timing.end(); + + ObjectToOffsetMapping mapping = this; + compareToVisitor = + new CompareToVisitorWithTypeTable(namingLens, this.strings::getInt, this.types::getInt) { + + @Override + public int visitDexField(DexField field1, DexField field2) { + return Integer.compare(mapping.fields.getInt(field1), mapping.fields.getInt(field2)); + } + + @Override + public int visitDexMethod(DexMethod method1, DexMethod method2) { + return Integer.compare( + mapping.methods.getInt(method1), mapping.methods.getInt(method2)); + } + }; } - private <T extends NamingLensComparable<T>> Comparator<T> compareWithStringTable() { - return (a, b) -> - CompareToVisitorWithStringTable.run( - a, b, namingLens, (ToIntFunction<DexString>) strings::getInt); + public CompareToVisitor getCompareToVisitor() { + return compareToVisitor; } - private <T extends NamingLensComparable<T>> Comparator<T> compareWithTypeTable() { - return (a, b) -> - CompareToVisitorWithTypeTable.run(a, b, namingLens, strings::getInt, types::getInt); + private <T extends StructuralItem<T>> Comparator<T> compare(CompareToVisitor visitor) { + return (a, b) -> a.acceptCompareTo(b, visitor); } private void setFirstJumboString(DexString string) {
diff --git a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java index fb642d6..7628702 100644 --- a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java +++ b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
@@ -6,8 +6,8 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.utils.ArrayUtils; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.Arrays; import java.util.function.Consumer; @@ -76,7 +76,7 @@ } @Override - public StructuralAccept<ParameterAnnotationsList> getStructuralAccept() { + public StructuralMapping<ParameterAnnotationsList> getStructuralMapping() { return ParameterAnnotationsList::specify; }
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java index d0948bf..0b5bc41 100644 --- a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java +++ b/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
@@ -33,7 +33,7 @@ } @Override - public boolean hasBeenMerged(DexType type) { + public boolean hasBeenMergedIntoDifferentType(DexType type) { return mergedClasses.containsKey(type); }
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java index 8fa6995..25879f1 100644 --- a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java +++ b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java
@@ -15,7 +15,7 @@ void forEachMergeGroup(BiConsumer<Set<DexType>, DexType> consumer); - boolean hasBeenMerged(DexType type); + boolean hasBeenMergedIntoDifferentType(DexType type); boolean verifyAllSourcesPruned(AppView<AppInfoWithLiveness> appView); @@ -23,17 +23,18 @@ * Determine if the class has been merged by the merged classes object. If the merged classes is * null then return false. */ - static boolean hasBeenMerged(MergedClasses mergedClasses, DexProgramClass clazz) { - return hasBeenMerged(mergedClasses, clazz.type); + static boolean hasBeenMergedIntoDifferentType( + MergedClasses mergedClasses, DexProgramClass clazz) { + return hasBeenMergedIntoDifferentType(mergedClasses, clazz.getType()); } /** * Determine if the class has been merged by the merged classes object. If the merged classes is * null then return false. */ - static boolean hasBeenMerged(MergedClasses mergedClasses, DexType type) { + static boolean hasBeenMergedIntoDifferentType(MergedClasses mergedClasses, DexType type) { if (mergedClasses != null) { - return mergedClasses.hasBeenMerged(type); + return mergedClasses.hasBeenMergedIntoDifferentType(type); } return false; }
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java index 1225127..5875506 100644 --- a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java +++ b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java
@@ -28,9 +28,9 @@ } @Override - public boolean hasBeenMerged(DexType type) { + public boolean hasBeenMergedIntoDifferentType(DexType type) { for (MergedClasses mergedClasses : collection) { - if (mergedClasses.hasBeenMerged(type)) { + if (mergedClasses.hasBeenMergedIntoDifferentType(type)) { return true; } }
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java index 7046e80..79e4ef7 100644 --- a/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java +++ b/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java
@@ -34,7 +34,7 @@ } @Override - public boolean hasBeenMerged(DexType type) { + public boolean hasBeenMergedIntoDifferentType(DexType type) { return false; }
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java index 4b25311..6ba32e9 100644 --- a/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java +++ b/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java
@@ -60,7 +60,7 @@ } @Override - public boolean hasBeenMerged(DexType type) { + public boolean hasBeenMergedIntoDifferentType(DexType type) { return hasBeenMergedIntoSubtype(type); }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java index 76ab41a..4d6d93f 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java
@@ -42,21 +42,17 @@ return mergedClasses.getKeys(type); } + @Override public boolean hasBeenMergedIntoDifferentType(DexType type) { return mergedClasses.hasKey(type); } - @Override - public boolean hasBeenMerged(DexType type) { - return hasBeenMergedIntoDifferentType(type); - } - public boolean isMergeTarget(DexType type) { return mergedClasses.hasValue(type); } public boolean hasBeenMergedOrIsMergeTarget(DexType type) { - return hasBeenMerged(type) || isMergeTarget(type); + return this.hasBeenMergedIntoDifferentType(type) || isMergeTarget(type); } Map<DexType, DexType> getForwardMap() {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java index 0fb2284..9612f98 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/DontInlinePolicy.java
@@ -29,6 +29,10 @@ private boolean disallowInlining(ProgramMethod method) { Code code = method.getDefinition().getCode(); + if (appView.appInfo().isNeverInlineMethod(method.getReference())) { + return true; + } + // For non-jar/cf code we currently cannot guarantee that markForceInline() will succeed. if (code == null || !code.isCfCode()) { return true;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java index fd8dbf7..8e52af1 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexField; +import com.android.tools.r8.graph.DexValue; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.code.BasicBlock; import com.android.tools.r8.ir.code.DominatorTree; @@ -85,6 +86,10 @@ return null; } + StaticFieldValueAnalysis asStaticFieldValueAnalysis() { + return null; + } + abstract boolean isSubjectToOptimization(DexEncodedField field); void recordFieldPut(DexEncodedField field, Instruction instruction) { @@ -148,6 +153,16 @@ boolean priorReadsWillReadSameValue = !classInitializerDefaultsResult.hasStaticValue(field) && fieldPut.value().isZero(); if (!priorReadsWillReadSameValue && fieldMaybeReadBeforeInstruction(field, fieldPut)) { + if (!isInstanceFieldValueAnalysis()) { + // At this point the value read in the field can be only the default static value, if read + // prior to the put, or the value put, if read after the put. We still want to record it + // because the default static value is typically null/0, so code present after a null/0 + // check can take advantage of the optimization. + DexValue valueBeforePut = classInitializerDefaultsResult.getStaticValue(field); + asStaticFieldValueAnalysis() + .updateFieldOptimizationInfoWith2Values( + field, fieldPut, fieldPut.value(), valueBeforePut); + } continue; } updateFieldOptimizationInfo(field, fieldPut, fieldPut.value());
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java index 443ac30..cc607ac 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
@@ -149,8 +149,8 @@ .getOptimizationInfo() .getInstanceInitializerInfo(invoke) .fieldInitializationInfos(); - for (DexEncodedField field : singleTarget.getHolder().instanceFields()) { - assert isSubjectToOptimization(field); + for (DexEncodedField field : + singleTarget.getHolder().getDirectAndIndirectInstanceFields(appView)) { InstanceFieldInitializationInfo info = infos.get(field); if (info.isArgumentInitializationInfo()) { int argumentIndex = info.asArgumentInitializationInfo().getArgumentIndex();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java index 9be6c55..3ab1305 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -9,16 +9,20 @@ import static com.android.tools.r8.ir.code.Opcodes.STATIC_PUT; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexValue; +import com.android.tools.r8.graph.DexValue.DexValueNull; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.analysis.value.AbstractValueFactory; import com.android.tools.r8.ir.analysis.value.EnumValuesObjectState; +import com.android.tools.r8.ir.analysis.value.NullOrAbstractValue; import com.android.tools.r8.ir.analysis.value.ObjectState; import com.android.tools.r8.ir.analysis.value.SingleFieldValue; import com.android.tools.r8.ir.code.ArrayPut; @@ -59,6 +63,11 @@ } @Override + StaticFieldValueAnalysis asStaticFieldValueAnalysis() { + return this; + } + + @Override void computeFieldOptimizationInfo(ClassInitializerDefaultsResult classInitializerDefaultsResult) { super.computeFieldOptimizationInfo(classInitializerDefaultsResult); @@ -98,19 +107,21 @@ @Override void updateFieldOptimizationInfo(DexEncodedField field, FieldInstruction fieldPut, Value value) { // Abstract value. - Value root = value.getAliasedValue(); - AbstractValue abstractValue = root.getAbstractValue(appView, context); - if (abstractValue.isUnknown()) { - feedback.recordFieldHasAbstractValue(field, appView, computeSingleFieldValue(field, root)); - } else { - feedback.recordFieldHasAbstractValue(field, appView, abstractValue); - } + feedback.recordFieldHasAbstractValue(field, appView, getOrComputeAbstractValue(value, field)); + setDynamicType(field, value, false); + } + + private void setDynamicType(DexEncodedField field, Value value, boolean maybeNull) { // Dynamic upper bound type. TypeElement fieldType = TypeElement.fromDexType(field.field.type, Nullability.maybeNull(), appView); TypeElement dynamicUpperBoundType = value.getDynamicUpperBoundType(appView); if (dynamicUpperBoundType.strictlyLessThan(fieldType, appView)) { + if (maybeNull && dynamicUpperBoundType.isDefinitelyNotNull()) { + assert dynamicUpperBoundType.isReferenceType(); + dynamicUpperBoundType = dynamicUpperBoundType.asReferenceType().asMaybeNull(); + } feedback.markFieldHasDynamicUpperBoundType(field, dynamicUpperBoundType); } @@ -118,10 +129,35 @@ ClassTypeElement dynamicLowerBoundType = value.getDynamicLowerBoundType(appView); if (dynamicLowerBoundType != null) { assert dynamicLowerBoundType.lessThanOrEqual(dynamicUpperBoundType, appView); + if (maybeNull && dynamicLowerBoundType.isDefinitelyNotNull()) { + dynamicLowerBoundType = dynamicLowerBoundType.asMaybeNull().asClassType(); + } feedback.markFieldHasDynamicLowerBoundType(field, dynamicLowerBoundType); } } + public void updateFieldOptimizationInfoWith2Values( + DexEncodedField field, FieldInstruction fieldPut, Value valuePut, DexValue valueBeforePut) { + // We are interested in the AbstractValue only if it's null or a value, so we can use the value + // if the code is protected by a null check. + if (valueBeforePut != DexValueNull.NULL) { + return; + } + feedback.recordFieldHasAbstractValue( + field, appView, NullOrAbstractValue.create(getOrComputeAbstractValue(valuePut, field))); + + setDynamicType(field, valuePut, true); + } + + private AbstractValue getOrComputeAbstractValue(Value value, DexEncodedField field) { + Value root = value.getAliasedValue(); + AbstractValue abstractValue = root.getAbstractValue(appView, context); + if (abstractValue.isUnknown()) { + return computeSingleFieldValue(field, root); + } + return abstractValue; + } + private SingleFieldValue computeSingleFieldValue(DexEncodedField field, Value value) { assert !value.hasAliasedValue(); SingleFieldValue result = computeSingleEnumFieldValue(value); @@ -273,8 +309,12 @@ } NewInstance newInstance = value.definition.asNewInstance(); + // Some enums have direct subclasses, and the subclass is instantiated here. if (newInstance.clazz != context.getHolderType()) { - return null; + DexClass dexClass = appView.definitionFor(newInstance.clazz); + if (dexClass == null || dexClass.superType != context.getHolderType()) { + return null; + } } if (value.hasDebugUsers() || value.hasPhiUsers()) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java index 41a0192..e53f27b 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -88,6 +88,14 @@ return false; } + public boolean isNullOrAbstractValue() { + return false; + } + + public NullOrAbstractValue asNullOrAbstractValue() { + return null; + } + public AbstractValue join(AbstractValue other) { if (isBottom() || other.isUnknown()) { return other; @@ -98,6 +106,12 @@ if (equals(other)) { return this; } + if (isNull()) { + return NullOrAbstractValue.create(other); + } + if (other.isNull()) { + return NullOrAbstractValue.create(this); + } return UnknownValue.getInstance(); }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/NullOrAbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/NullOrAbstractValue.java new file mode 100644 index 0000000..2bf329d --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/analysis/value/NullOrAbstractValue.java
@@ -0,0 +1,68 @@ +// 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.analysis.value; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.shaking.AppInfoWithLiveness; + +public class NullOrAbstractValue extends AbstractValue { + + private final AbstractValue value; + + private NullOrAbstractValue(AbstractValue value) { + this.value = value; + } + + public static AbstractValue create(AbstractValue value) { + if (value.isBottom() || value.isUnknown() || value.isNull() || value.isNullOrAbstractValue()) { + return value; + } + return new NullOrAbstractValue(value); + } + + @Override + public boolean isNonTrivial() { + return true; + } + + @Override + public boolean isNullOrAbstractValue() { + return true; + } + + @Override + public NullOrAbstractValue asNullOrAbstractValue() { + return this; + } + + public AbstractValue getNonNullValue() { + return value; + } + + @Override + public NullOrAbstractValue rewrittenWithLens( + AppView<AppInfoWithLiveness> appView, GraphLens lens) { + return new NullOrAbstractValue(value.rewrittenWithLens(appView, lens)); + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } + return this.getClass() == o.getClass() && value.equals(((NullOrAbstractValue) o).value); + } + + @Override + public int hashCode() { + return value.hashCode() * 7; + } + + @Override + public String toString() { + return "Null or " + value.toString(); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueType.java b/src/main/java/com/android/tools/r8/ir/code/ValueType.java index 8b06849..0ae9459 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ValueType.java +++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -9,8 +9,9 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement; import com.android.tools.r8.ir.analysis.type.TypeElement; -import com.android.tools.r8.utils.structural.StructuralAccept; import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; +import com.android.tools.r8.utils.structural.StructuralSpecification; public enum ValueType implements StructuralItem<ValueType> { OBJECT, @@ -19,14 +20,18 @@ LONG, DOUBLE; + private static void specify(StructuralSpecification<ValueType, ?> spec) { + spec.withInt(Enum::ordinal); + } + @Override public ValueType self() { return this; } @Override - public StructuralAccept<ValueType> getStructuralAccept() { - return spec -> spec.withInt(Enum::ordinal); + public StructuralMapping<ValueType> getStructuralMapping() { + return ValueType::specify; } public boolean isObject() {
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 0974715..2ef58cd 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
@@ -550,10 +550,20 @@ definition.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive); convertMethod(method); }); + // The class file version is downgraded after compilation. Some of the desugaring might need + // the initial class file version to determine how far a method can be downgraded. + if (clazz.hasClassFileVersion()) { + clazz.downgradeInitialClassFileVersion( + appView.options().classFileVersionAfterDesugaring(clazz.getInitialClassFileVersion())); + } } private void convertMethod(ProgramMethod method) { DexEncodedMethod definition = method.getDefinition(); + if (definition.hasClassFileVersion()) { + definition.downgradeClassFileVersion( + appView.options().classFileVersionAfterDesugaring(definition.getClassFileVersion())); + } if (definition.getCode() == null) { return; }
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 6c1c172..bff68b1 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
@@ -5,6 +5,7 @@ package com.android.tools.r8.ir.desugar; import com.android.tools.r8.DesugarGraphConsumer; +import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.Unimplemented; @@ -54,6 +55,7 @@ import com.android.tools.r8.utils.Pair; import com.android.tools.r8.utils.StringDiagnostic; import com.android.tools.r8.utils.collections.SortedProgramMethodSet; +import com.android.tools.r8.utils.structural.Ordered; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Arrays; @@ -214,6 +216,21 @@ return emulatedInterfaces.get(itf); } + private void leavingStaticInvokeToInterface( + DexProgramClass holder, DexEncodedMethod encodedMethod) { + // When leaving static interface method invokes possibly upgrade the class file + // version, but don't go above the initial class file version. If the input was + // 1.7 or below, this will make a VerificationError on the input a VerificationError + // on the output. If the input was 1.8 or above the runtime behaviour (potential ICCE) + // will remain the same. + if (holder.hasClassFileVersion()) { + encodedMethod.upgradeClassFileVersion( + Ordered.min(CfVersion.V1_8, holder.getInitialClassFileVersion())); + } else { + encodedMethod.upgradeClassFileVersion(CfVersion.V1_8); + } + } + // Rewrites the references to static and default interface methods. // NOTE: can be called for different methods concurrently. public void rewriteMethodReferences(IRCode code) { @@ -257,6 +274,9 @@ // NOTE: leave unchanged those calls to undefined targets. This may lead to runtime // exception but we can not report it as error since it can also be the intended // behavior. + if (invokeStatic.getInterfaceBit()) { + leavingStaticInvokeToInterface(context.getHolder(), encodedMethod); + } warnMissingType(encodedMethod.method, method.holder); } else if (clazz.isInterface()) { if (isNonDesugaredLibraryClass(clazz)) { @@ -304,14 +324,25 @@ invokeStatic.outValue(), invokeStatic.arguments())); synchronized (synthesizedMethods) { + // The synthetic dispatch class has static interface method invokes, so set + // the class file version accordingly. + newProgramMethod.getDefinition().upgradeClassFileVersion(CfVersion.V1_8); synthesizedMethods.add(newProgramMethod); } + } else { + // When leaving static interface method invokes upgrade the class file version. + encodedMethod.upgradeClassFileVersion(CfVersion.V1_8); } } else { instructions.replaceCurrentInstruction( new InvokeStatic(staticAsMethodOfCompanionClass(method), invokeStatic.outValue(), invokeStatic.arguments())); } + } else { + assert !clazz.isInterface(); + if (invokeStatic.getInterfaceBit()) { + leavingStaticInvokeToInterface(context.getHolder(), encodedMethod); + } } continue; }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java index 88e1200..abe232f 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -213,7 +213,7 @@ ParameterAnnotationsList.empty(), code, true, - iface.hasClassFileVersion() ? iface.getInitialClassFileVersion() : null); + iface.getInitialClassFileVersion()); } private void processVirtualInterfaceMethods(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java index b1d8880..23342df 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -89,6 +89,15 @@ } return false; } + + public DexValue getStaticValue(DexEncodedField field) { + assert hasStaticValue(field); + assert field.isStatic(); + if (fieldsWithStaticValues != null && fieldsWithStaticValues.containsKey(field)) { + return fieldsWithStaticValues.get(field); + } + return field.getStaticValue(); + } } private static class WaveDoneAction implements Action {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java index 033a233..b7addaa 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -14,13 +14,10 @@ import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfo; -import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.TypeAnalysis; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; -import com.android.tools.r8.ir.analysis.value.ObjectState; import com.android.tools.r8.ir.analysis.value.SingleNumberValue; import com.android.tools.r8.ir.analysis.value.SingleStringValue; import com.android.tools.r8.ir.code.ArrayGet; @@ -37,7 +34,6 @@ import com.android.tools.r8.ir.code.InvokeVirtual; import com.android.tools.r8.ir.code.StaticGet; import com.android.tools.r8.ir.code.Value; -import com.android.tools.r8.ir.optimize.SwitchMapCollector; import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.utils.ArrayUtils; @@ -103,40 +99,20 @@ FieldOptimizationInfo optimizationInfo = definition.getOptimizationInfo(); AbstractValue abstractValue = optimizationInfo.getAbstractValue(); - if (!abstractValue.isSingleFieldValue()) { - continue; - } - - ObjectState objectState = abstractValue.asSingleFieldValue().getState(); - if (objectState.isEmpty()) { - continue; - } Value outValue = methodWithReceiver.outValue(); if (isOrdinalInvoke) { - DexField ordinalField = appView.dexItemFactory().enumMembers.ordinalField; - DexEncodedField ordinalDefinition = - ordinalField.lookupOnClass(appView.definitionForHolder(ordinalField)); - if (ordinalDefinition != null) { - SingleNumberValue ordinalValue = - objectState.getAbstractFieldValue(ordinalDefinition).asSingleNumberValue(); + SingleNumberValue ordinalValue = + getOrdinalValue(code, abstractValue, methodWithReceiver.getReceiver().isNeverNull()); if (ordinalValue != null) { iterator.replaceCurrentInstruction( new ConstNumber(outValue, ordinalValue.getValue())); - } } continue; } - DexField nameField = appView.dexItemFactory().enumMembers.nameField; - DexEncodedField nameDefinition = - nameField.lookupOnClass(appView.definitionForHolder(nameField)); - if (nameField == null) { - continue; - } - SingleStringValue nameValue = - objectState.getAbstractFieldValue(nameDefinition).asSingleStringValue(); + getNameValue(code, abstractValue, methodWithReceiver.getReceiver().isNeverNull()); if (nameValue == null) { continue; } @@ -228,7 +204,7 @@ continue; } - Int2IntMap ordinalToTargetMap = computeOrdinalToTargetMap(switchInsn, info); + Int2IntMap ordinalToTargetMap = computeOrdinalToTargetMap(code, switchInsn, info); if (ordinalToTargetMap == null) { continue; } @@ -315,24 +291,62 @@ } } - private Int2IntMap computeOrdinalToTargetMap(IntSwitch switchInsn, EnumSwitchInfo info) { - Int2IntMap ordinalToTargetMap = new Int2IntArrayMap(switchInsn.numberOfKeys()); + private Int2IntArrayMap computeOrdinalToTargetMap( + IRCode code, IntSwitch switchInsn, EnumSwitchInfo info) { + Int2IntArrayMap ordinalToTargetMap = new Int2IntArrayMap(switchInsn.numberOfKeys()); for (int i = 0; i < switchInsn.numberOfKeys(); i++) { assert switchInsn.targetBlockIndices()[i] != switchInsn.getFallthroughBlockIndex(); DexField field = info.indexMap.get(switchInsn.getKey(i)); - EnumValueInfo valueInfo = info.valueInfoMap.getEnumValueInfo(field); - if (valueInfo != null) { - if (appView.appInfo().isPinned(field)) { + DexEncodedField enumInstanceField = + appView.appInfo().resolveField(field, code.context()).getResolvedField(); + if (enumInstanceField == null) { + // The switch map refers to a field on the enum that does not exist in this compilation. + } else { + AbstractValue abstractValue = enumInstanceField.getOptimizationInfo().getAbstractValue(); + // The rewriting effectively leaves in place the myEnum.ordinal() call, so if the value + // is null, the same NPE happens at runtime, we can assume the value is non null in the + // switch map after the ordinal call. + SingleNumberValue ordinalValue = getOrdinalValue(code, abstractValue, true); + if (ordinalValue == null) { return null; } - ordinalToTargetMap.put(valueInfo.ordinal, switchInsn.targetBlockIndices()[i]); - } else { - // The switch map refers to a field on the enum that does not exist in this compilation. + ordinalToTargetMap.put( + ordinalValue.asSingleNumberValue().getIntValue(), switchInsn.targetBlockIndices()[i]); } } return ordinalToTargetMap; } + private SingleStringValue getNameValue( + IRCode code, AbstractValue abstractValue, boolean neverNull) { + AbstractValue ordinalValue = + getEnumFieldValue(code, abstractValue, factory.enumMembers.nameField, neverNull); + return ordinalValue == null ? null : ordinalValue.asSingleStringValue(); + } + + private SingleNumberValue getOrdinalValue( + IRCode code, AbstractValue abstractValue, boolean neverNull) { + AbstractValue ordinalValue = + getEnumFieldValue(code, abstractValue, factory.enumMembers.ordinalField, neverNull); + return ordinalValue == null ? null : ordinalValue.asSingleNumberValue(); + } + + private AbstractValue getEnumFieldValue( + IRCode code, AbstractValue abstractValue, DexField field, boolean neverNull) { + if (neverNull && abstractValue.isNullOrAbstractValue()) { + abstractValue = abstractValue.asNullOrAbstractValue().getNonNullValue(); + } + if (!abstractValue.isSingleFieldValue()) { + return null; + } + DexEncodedField encodedField = + appView.appInfo().resolveField(field, code.context()).getResolvedField(); + if (encodedField == null) { + return null; + } + return abstractValue.asSingleFieldValue().getState().getAbstractFieldValue(encodedField); + } + private static final class EnumSwitchInfo { final DexType enumClass; @@ -340,21 +354,18 @@ final Instruction arrayGet; public final Instruction staticGet; final Int2ReferenceMap<DexField> indexMap; - final EnumValueInfoMap valueInfoMap; private EnumSwitchInfo( DexType enumClass, Instruction ordinalInvoke, Instruction arrayGet, Instruction staticGet, - Int2ReferenceMap<DexField> indexMap, - EnumValueInfoMap valueInfoMap) { + Int2ReferenceMap<DexField> indexMap) { this.enumClass = enumClass; this.ordinalInvoke = ordinalInvoke; this.arrayGet = arrayGet; this.staticGet = staticGet; this.indexMap = indexMap; - this.valueInfoMap = valueInfoMap; } } @@ -371,8 +382,7 @@ * * </blockquote> * - * and extracts the components and the index and ordinal maps. See {@link - * EnumValueInfoMapCollector} and {@link SwitchMapCollector} for details. + * and extracts the components and the index and ordinal maps. */ private EnumSwitchInfo analyzeSwitchOverEnum(IntSwitch switchInsn) { Instruction input = switchInsn.inValues().get(0).definition; @@ -412,10 +422,6 @@ } // Due to member rebinding, only the fields are certain to provide the actual enums class. DexType enumType = indexMap.values().iterator().next().holder; - EnumValueInfoMap valueInfoMap = appView.appInfo().getEnumValueInfoMap(enumType); - if (valueInfoMap == null) { - return null; - } - return new EnumSwitchInfo(enumType, ordinalInvoke, arrayGet, staticGet, indexMap, valueInfoMap); + return new EnumSwitchInfo(enumType, ordinalInvoke, arrayGet, staticGet, indexMap); } }
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java index 58c9f2d..25688ce 100644 --- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java +++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -263,10 +263,13 @@ || options.isDesugaredLibraryCompilation() || options.cfToCfDesugar : "Expected class file version for " + method.method.toSourceString(); - // TODO(b/146424042): We may call static methods on interface classes so we have to go for - // Java 8. - assert MIN_VERSION_FOR_COMPILER_GENERATED_CODE.isLessThan(CfVersion.V1_8); - return options.cfToCfDesugar ? CfVersion.V1_8 : MIN_VERSION_FOR_COMPILER_GENERATED_CODE; + assert MIN_VERSION_FOR_COMPILER_GENERATED_CODE.isLessThan( + options.classFileVersionAfterDesugaring(InternalOptions.SUPPORTED_CF_VERSION)); + // Any desugaring rewrites which cannot meet the default class file version after + // desugaring must upgrade the class file version during desugaring. + return options.cfToCfDesugar + ? options.classFileVersionAfterDesugaring(InternalOptions.SUPPORTED_CF_VERSION) + : MIN_VERSION_FOR_COMPILER_GENERATED_CODE; } return method.getClassFileVersion(); }
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java index b4760c1..bcbba53 100644 --- a/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java +++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingConstraintGraph.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.repackaging; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexDefinition; import com.android.tools.r8.graph.DexEncodedMember; import com.android.tools.r8.graph.DexEncodedMethod; @@ -41,10 +42,13 @@ private final ProgramPackage pkg; private final Map<DexDefinition, Node> nodes = new IdentityHashMap<>(); private final Set<Node> pinnedNodes = Sets.newIdentityHashSet(); + private final Node libraryBoundaryNode; public RepackagingConstraintGraph(AppView<AppInfoWithLiveness> appView, ProgramPackage pkg) { this.appView = appView; this.pkg = pkg; + libraryBoundaryNode = createNode(appView.definitionFor(appView.dexItemFactory().objectType)); + pinnedNodes.add(libraryBoundaryNode); } /** Returns true if all classes in the package can be repackaged. */ @@ -75,6 +79,13 @@ } Node getNode(DexDefinition definition) { + if (definition.isNotProgramDefinition(appView)) { + String packageDescriptor = definition.getContextType().getPackageDescriptor(); + if (packageDescriptor.equals(pkg.getPackageDescriptor())) { + return libraryBoundaryNode; + } + return null; + } return nodes.get(definition); } @@ -110,7 +121,11 @@ } // Trace the references to the inner and outer classes. - clazz.getInnerClasses().forEach(registry::registerInnerClassAttribute); + clazz + .getInnerClasses() + .forEach( + innerClassAttribute -> + registry.registerInnerClassAttribute(clazz, innerClassAttribute)); // Trace the references from the enclosing method attribute. EnclosingMethodAttribute attr = clazz.getEnclosingMethodAttribute(); @@ -137,8 +152,8 @@ definition.getProto().forEachType(registry::registerTypeReference); // Check if this overrides a package-private method. - DexProgramClass superClass = - appView.programDefinitionFor(method.getHolder().getSuperType(), method.getHolder()); + DexClass superClass = + appView.definitionFor(method.getHolder().getSuperType(), method.getHolder()); if (superClass != null) { registry.registerMemberAccess( appView.appInfo().resolveMethodOn(superClass, method.getReference()));
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java index 57361d3..91484f7 100644 --- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java +++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ClassAccessFlags; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexClassAndMember; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; @@ -19,7 +20,6 @@ import com.android.tools.r8.graph.InnerClassAttribute; import com.android.tools.r8.graph.MemberResolutionResult; import com.android.tools.r8.graph.ProgramDefinition; -import com.android.tools.r8.graph.ProgramMember; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.ResolutionResult; import com.android.tools.r8.graph.SuccessfulMemberResolutionResult; @@ -48,7 +48,7 @@ this.node = constraintGraph.getNode(context.getDefinition()); } - private boolean isOnlyAccessibleFromSamePackage(DexProgramClass referencedClass) { + private boolean isOnlyAccessibleFromSamePackage(DexClass referencedClass) { ClassAccessFlags accessFlags = referencedClass.getAccessFlags(); if (accessFlags.isPackagePrivate()) { return true; @@ -60,8 +60,8 @@ return false; } - private boolean isOnlyAccessibleFromSamePackage(ProgramMember<?, ?> member) { - AccessFlags<?> accessFlags = member.getDefinition().getAccessFlags(); + private boolean isOnlyAccessibleFromSamePackage(DexClassAndMember<?, ?> member) { + AccessFlags<?> accessFlags = member.getAccessFlags(); if (accessFlags.isPackagePrivate()) { return true; } @@ -96,22 +96,21 @@ } // Check access to the initial resolution holder. - registerTypeAccess(successfulResolutionResult.getInitialResolutionHolder()); + registerClassTypeAccess(successfulResolutionResult.getInitialResolutionHolder()); // Similarly, check access to the resolved member. - ProgramMember<?, ?> resolvedMember = - successfulResolutionResult.getResolvedMember().asProgramMember(appInfo); - if (resolvedMember != null) { + DexClassAndMember<?, ?> resolutionPair = successfulResolutionResult.getResolutionPair(); + if (resolutionPair != null) { RepackagingConstraintGraph.Node resolvedMemberNode = - constraintGraph.getNode(resolvedMember.getDefinition()); - if (resolvedMemberNode != null && isOnlyAccessibleFromSamePackage(resolvedMember)) { + constraintGraph.getNode(resolutionPair.getDefinition()); + if (resolvedMemberNode != null && isOnlyAccessibleFromSamePackage(resolutionPair)) { node.addNeighbor(resolvedMemberNode); } } } private void registerTypeAccess(DexType type) { - registerTypeAccess(type, this::registerTypeAccess); + registerTypeAccess(type, this::registerClassTypeAccess); } private void registerTypeAccess(DexType type, Consumer<DexClass> consumer) { @@ -129,20 +128,17 @@ } } - private void registerTypeAccess(DexClass clazz) { - registerTypeAccess(clazz, this::isOnlyAccessibleFromSamePackage); + private void registerClassTypeAccess(DexClass clazz) { + registerClassTypeAccess(clazz, this::isOnlyAccessibleFromSamePackage); } - private void registerTypeAccess(DexClass clazz, Predicate<DexProgramClass> predicate) { + private void registerClassTypeAccess(DexClass clazz, Predicate<DexClass> predicate) { // We only want to connect the current method node to the class node if the access requires the - // two nodes to be in the same package. Therefore, we ignore accesses to non-program classes - // and program classes outside the current package. - DexProgramClass programClass = clazz.asProgramClass(); - if (programClass != null) { - RepackagingConstraintGraph.Node classNode = constraintGraph.getNode(programClass); - if (classNode != null && predicate.test(programClass)) { - node.addNeighbor(classNode); - } + // two nodes to be in the same package. Therefore, we ignore accesses to program classes outside + // the current package. + RepackagingConstraintGraph.Node classNode = constraintGraph.getNode(clazz); + if (classNode != null && predicate.test(clazz)) { + node.addNeighbor(classNode); } } @@ -218,21 +214,22 @@ if (enclosingMethodAttribute.getEnclosingClass() != null) { registerTypeAccess( enclosingMethodAttribute.getEnclosingClass(), - clazz -> registerTypeAccess(clazz, alwaysTrue())); + clazz -> registerClassTypeAccess(clazz, alwaysTrue())); } if (enclosingMethodAttribute.getEnclosingMethod() != null) { ProgramMethod method = registerMethodReference(enclosingMethodAttribute.getEnclosingMethod()); if (method != null) { - registerTypeAccess(method.getHolder(), alwaysTrue()); + registerClassTypeAccess(method.getHolder(), alwaysTrue()); } } } - public void registerInnerClassAttribute(InnerClassAttribute innerClassAttribute) { + public void registerInnerClassAttribute( + DexProgramClass outer, InnerClassAttribute innerClassAttribute) { // For references in inner class attributes we add an edge from the context to the referenced // class even if the referenced class would be accessible from another package, to make sure // that we don't split such classes into different packages. innerClassAttribute.forEachType( - type -> registerTypeAccess(type, clazz -> registerTypeAccess(clazz, alwaysTrue()))); + type -> registerTypeAccess(type, clazz -> registerClassTypeAccess(clazz, alwaysTrue()))); } }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java index 4d621a3..6fa737b 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -282,6 +282,8 @@ methodBuilder .setAccessFlags(definition.accessFlags) .setProto(definition.getProto()) + .setClassFileVersion( + definition.hasClassFileVersion() ? definition.getClassFileVersion() : null) .setCode(m -> definition.getCode()); }); DexProgramClass externalSyntheticClass = builder.build();
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java index ee17db8..9fcc7d9 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.synthesis; +import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.graph.Code; import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexEncodedMethod; @@ -21,6 +22,7 @@ private final SyntheticClassBuilder parent; private final String name; private DexProto proto = null; + private CfVersion classFileVersion; private SyntheticCodeGenerator codeGenerator = null; private MethodAccessFlags accessFlags = null; @@ -34,6 +36,11 @@ return this; } + public SyntheticMethodBuilder setClassFileVersion(CfVersion classFileVersion) { + this.classFileVersion = classFileVersion; + return this; + } + public SyntheticMethodBuilder setCode(SyntheticCodeGenerator codeGenerator) { this.codeGenerator = codeGenerator; return this; @@ -55,7 +62,8 @@ DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), getCodeObject(methodSignature), - isCompilerSynthesized); + isCompilerSynthesized, + classFileVersion); assert isValidSyntheticMethod(method); return method; }
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 f4cdbaa..cd3a2db 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -63,6 +63,7 @@ import com.android.tools.r8.utils.IROrdering.IdentityIROrdering; import com.android.tools.r8.utils.IROrdering.NondeterministicIROrdering; import com.android.tools.r8.utils.collections.SortedProgramMethodSet; +import com.android.tools.r8.utils.structural.Ordered; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Equivalence.Wrapper; import com.google.common.collect.ImmutableList; @@ -595,6 +596,10 @@ || getProguardConfiguration().getKeepAttributes().innerClasses; } + public boolean canUseInputStackMaps() { + return testing.readInputStackMaps ? testing.readInputStackMaps : isGeneratingClassFiles(); + } + public boolean printCfg = false; public String printCfgFile; public boolean ignoreMissingClasses = false; @@ -1529,6 +1534,15 @@ return (isGeneratingClassFiles() && !cfToCfDesugar) || hasMinApi(AndroidApiLevel.K); } + public CfVersion classFileVersionAfterDesugaring(CfVersion version) { + if (!isDesugaring()) { + return version; + } + CfVersion maxVersionAfterDesugar = + canUseDefaultAndStaticInterfaceMethods() ? CfVersion.V1_8 : CfVersion.V1_7; + return Ordered.min(maxVersionAfterDesugar, version); + } + // The Apache Harmony-based AssertionError constructor which takes an Object on API 15 and older // calls the Error supertype constructor with null as the exception cause. This prevents // subsequent calls to initCause() because its implementation checks that cause==this before
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java index 32221a0..a0b2104 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java +++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java
@@ -17,45 +17,48 @@ /** Base class for a visitor implementing compareTo on a structural item. */ public abstract class CompareToVisitor { - public abstract void visitBool(boolean value1, boolean value2); + public abstract int visitBool(boolean value1, boolean value2); - public abstract void visitInt(int value1, int value2); + public abstract int visitInt(int value1, int value2); - public abstract void visitLong(long value1, long value2); + public abstract int visitLong(long value1, long value2); - public abstract void visitFloat(float value1, float value2); + public abstract int visitFloat(float value1, float value2); - public abstract void visitDouble(double value1, double value2); + public abstract int visitDouble(double value1, double value2); /** Base for visiting an enumeration of items. */ - public abstract <S> void visitItemIterator( + public abstract <S> int visitItemIterator( Iterator<S> it1, Iterator<S> it2, CompareToAccept<S> compareToAccept); - public final <S extends StructuralItem<S>> void visitItemArray(S[] items1, S[] items2) { - visitItemCollection(Arrays.asList(items1), Arrays.asList(items2)); + public final <S extends StructuralItem<S>> int visitItemArray(S[] items1, S[] items2) { + return visitItemCollection(Arrays.asList(items1), Arrays.asList(items2)); } - public final <S extends StructuralItem<S>> void visitItemCollection( + public final <S extends StructuralItem<S>> int visitItemCollection( Collection<S> items1, Collection<S> items2) { - visitItemIterator(items1.iterator(), items2.iterator(), S::acceptCompareTo); + return visitItemIterator( + items1.iterator(), + items2.iterator(), + (s, other, visitor) -> s.acceptCompareTo(other, visitor)); } - public abstract void visitDexString(DexString string1, DexString string2); + public abstract int visitDexString(DexString string1, DexString string2); - public abstract void visitDexType(DexType type1, DexType type2); + public abstract int visitDexType(DexType type1, DexType type2); - public void visitDexField(DexField field1, DexField field2) { - visit(field1, field2, field1.getStructuralAccept()); + public int visitDexField(DexField field1, DexField field2) { + return visit(field1, field2, field1.getStructuralMapping()); } - public void visitDexMethod(DexMethod method1, DexMethod method2) { - visit(method1, method2, method1.getStructuralAccept()); + public int visitDexMethod(DexMethod method1, DexMethod method2) { + return visit(method1, method2, method1.getStructuralMapping()); } - public abstract void visitDexReference(DexReference reference1, DexReference reference2); + public abstract int visitDexReference(DexReference reference1, DexReference reference2); - public abstract <S> void visit(S item1, S item2, StructuralAccept<S> accept); + public abstract <S> int visit(S item1, S item2, StructuralMapping<S> accept); @Deprecated - public abstract <S> void visit(S item1, S item2, Comparator<S> comparator); + public abstract <S> int visit(S item1, S item2, Comparator<S> comparator); }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java index 1f517d0..ee264cc 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java +++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java
@@ -18,102 +18,75 @@ /** Base class to share most visiting methods */ public abstract class CompareToVisitorBase extends CompareToVisitor { - private int order = 0; - - public final boolean stillEqual() { - return order == 0; + @Override + public final int visitBool(boolean value1, boolean value2) { + return Boolean.compare(value1, value2); } - public final int getOrder() { + @Override + public final int visitInt(int value1, int value2) { + return Integer.compare(value1, value2); + } + + @Override + public int visitLong(long value1, long value2) { + return Long.compare(value1, value2); + } + + @Override + public int visitFloat(float value1, float value2) { + return Float.compare(value1, value2); + } + + @Override + public int visitDouble(double value1, double value2) { + return Double.compare(value1, value2); + } + + @Override + public <S> int visitItemIterator( + Iterator<S> it1, Iterator<S> it2, CompareToAccept<S> compareToAccept) { + int order = 0; + while (order == 0 && it1.hasNext() && it2.hasNext()) { + order = compareToAccept.acceptCompareTo(it1.next(), it2.next(), this); + } + if (order == 0) { + order = visitBool(it1.hasNext(), it2.hasNext()); + } return order; } - public final void setOrder(int order) { - this.order = order; + @Override + public int visitDexString(DexString string1, DexString string2) { + return string1.compareTo(string2); } @Override - public final void visitBool(boolean value1, boolean value2) { - if (stillEqual()) { - setOrder(Boolean.compare(value1, value2)); - } - } - - @Override - public final void visitInt(int value1, int value2) { - if (stillEqual()) { - setOrder(Integer.compare(value1, value2)); - } - } - - @Override - public void visitLong(long value1, long value2) { - if (stillEqual()) { - setOrder(Long.compare(value1, value2)); - } - } - - @Override - public void visitFloat(float value1, float value2) { - if (stillEqual()) { - setOrder(Float.compare(value1, value2)); - } - } - - @Override - public void visitDouble(double value1, double value2) { - if (stillEqual()) { - setOrder(Double.compare(value1, value2)); - } - } - - @Override - public <S> void visitItemIterator( - Iterator<S> it1, Iterator<S> it2, CompareToAccept<S> compareToAccept) { - while (stillEqual() && it1.hasNext() && it2.hasNext()) { - compareToAccept.acceptCompareTo(it1.next(), it2.next(), this); - } - if (stillEqual()) { - visitBool(it1.hasNext(), it2.hasNext()); - } - } - - @Override - public void visitDexString(DexString string1, DexString string2) { - if (stillEqual()) { - setOrder(string1.compareTo(string2)); - } - } - - @Override - public void visitDexReference(DexReference reference1, DexReference reference2) { - if (stillEqual()) { - visitInt(reference1.referenceTypeOrder(), reference2.referenceTypeOrder()); - if (stillEqual()) { - assert reference1.getClass() == reference2.getClass(); - if (reference1.isDexType()) { - visitDexType(reference1.asDexType(), reference2.asDexType()); - } else if (reference1.isDexField()) { - visitDexField(reference1.asDexField(), reference2.asDexField()); - } else { - visitDexMethod(reference1.asDexMethod(), reference2.asDexMethod()); - } + public int visitDexReference(DexReference reference1, DexReference reference2) { + int order = visitInt(reference1.referenceTypeOrder(), reference2.referenceTypeOrder()); + if (order == 0) { + assert reference1.getClass() == reference2.getClass(); + if (reference1.isDexType()) { + order = visitDexType(reference1.asDexType(), reference2.asDexType()); + } else if (reference1.isDexField()) { + order = visitDexField(reference1.asDexField(), reference2.asDexField()); + } else { + order = visitDexMethod(reference1.asDexMethod(), reference2.asDexMethod()); } } + return order; } @Override - public final <S> void visit(S item1, S item2, Comparator<S> comparator) { - if (stillEqual()) { - setOrder(comparator.compare(item1, item2)); - } + public final <S> int visit(S item1, S item2, Comparator<S> comparator) { + return comparator.compare(item1, item2); } @Override - public final <S> void visit(S item1, S item2, StructuralAccept<S> accept) { - if (stillEqual()) { - accept.apply(new ItemSpecification<>(item1, item2, this)); - } + public final <S> int visit(S item1, S item2, StructuralMapping<S> accept) { + ItemSpecification<S> itemVisitor = new ItemSpecification<>(item1, item2, this); + accept.apply(itemVisitor); + return itemVisitor.order; } private static class ItemSpecification<T> @@ -122,6 +95,7 @@ private final CompareToVisitorBase parent; private final T item1; private final T item2; + private int order = 0; private ItemSpecification(T item1, T item2, CompareToVisitorBase parent) { this.item1 = item1; @@ -138,47 +112,47 @@ @Override public ItemSpecification<T> withBool(Predicate<T> getter) { - if (parent.stillEqual()) { - parent.visitBool(getter.test(item1), getter.test(item2)); + if (order == 0) { + order = parent.visitBool(getter.test(item1), getter.test(item2)); } return this; } @Override public ItemSpecification<T> withInt(ToIntFunction<T> getter) { - if (parent.stillEqual()) { - parent.visitInt(getter.applyAsInt(item1), getter.applyAsInt(item2)); + if (order == 0) { + order = parent.visitInt(getter.applyAsInt(item1), getter.applyAsInt(item2)); } return this; } @Override public ItemSpecification<T> withLong(ToLongFunction<T> getter) { - if (parent.stillEqual()) { - parent.visitLong(getter.applyAsLong(item1), getter.applyAsLong(item2)); + if (order == 0) { + order = parent.visitLong(getter.applyAsLong(item1), getter.applyAsLong(item2)); } return this; } @Override public ItemSpecification<T> withDouble(ToDoubleFunction<T> getter) { - if (parent.stillEqual()) { - parent.visitDouble(getter.applyAsDouble(item1), getter.applyAsDouble(item2)); + if (order == 0) { + order = parent.visitDouble(getter.applyAsDouble(item1), getter.applyAsDouble(item2)); } return this; } @Override public ItemSpecification<T> withIntArray(Function<T, int[]> getter) { - if (parent.stillEqual()) { + if (order == 0) { int[] is1 = getter.apply(item1); int[] is2 = getter.apply(item2); int minLength = Math.min(is1.length, is2.length); - for (int i = 0; i < minLength && parent.stillEqual(); i++) { - parent.visitInt(is1[i], is2[i]); + for (int i = 0; i < minLength && order == 0; i++) { + order = parent.visitInt(is1[i], is2[i]); } - if (parent.stillEqual()) { - parent.visitInt(is1.length, is2.length); + if (order == 0) { + order = parent.visitInt(is1.length, is2.length); } } return this; @@ -190,13 +164,13 @@ Function<T, S> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) { - if (parent.stillEqual()) { + if (order == 0) { boolean test1 = predicate.test(item1); boolean test2 = predicate.test(item2); if (test1 && test2) { - compare.acceptCompareTo(getter.apply(item1), getter.apply(item2), parent); + order = compare.acceptCompareTo(getter.apply(item1), getter.apply(item2), parent); } else { - parent.visitBool(test1, test2); + order = parent.visitBool(test1, test2); } } return this; @@ -205,8 +179,8 @@ @Override protected <S> ItemSpecification<T> withItemIterator( Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) { - if (parent.stillEqual()) { - parent.visitItemIterator(getter.apply(item1), getter.apply(item2), compare); + if (order == 0) { + order = parent.visitItemIterator(getter.apply(item1), getter.apply(item2), compare); } return this; }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java index 5295766..f581065 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java +++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java
@@ -11,15 +11,14 @@ public class CompareToVisitorWithNamingLens extends CompareToVisitorBase { - public static <T> int run(T item1, T item2, NamingLens namingLens, StructuralAccept<T> visit) { + public static <T> int run(T item1, T item2, NamingLens namingLens, StructuralMapping<T> visit) { return run(item1, item2, namingLens, (i1, i2, visitor) -> visitor.visit(i1, i2, visit)); } public static <T> int run( T item1, T item2, NamingLens namingLens, CompareToAccept<T> compareToAccept) { CompareToVisitorWithNamingLens state = new CompareToVisitorWithNamingLens(namingLens); - compareToAccept.acceptCompareTo(item1, item2, state); - return state.getOrder(); + return compareToAccept.acceptCompareTo(item1, item2, state); } private final NamingLens namingLens; @@ -29,35 +28,35 @@ } @Override - public void visitDexType(DexType type1, DexType type2) { - if (stillEqual()) { - namingLens.lookupDescriptor(type1).acceptCompareTo(namingLens.lookupDescriptor(type2), this); - } + public int visitDexType(DexType type1, DexType type2) { + return namingLens + .lookupDescriptor(type1) + .acceptCompareTo(namingLens.lookupDescriptor(type2), this); } @Override - public void visitDexField(DexField field1, DexField field2) { - if (stillEqual()) { - field1.holder.acceptCompareTo(field2.holder, this); - if (stillEqual()) { - namingLens.lookupName(field1).acceptCompareTo(namingLens.lookupName(field2), this); - if (stillEqual()) { - field1.type.acceptCompareTo(field2.type, this); - } - } + public int visitDexField(DexField field1, DexField field2) { + int order = field1.holder.acceptCompareTo(field2.holder, this); + if (order != 0) { + return order; } + order = namingLens.lookupName(field1).acceptCompareTo(namingLens.lookupName(field2), this); + if (order != 0) { + return order; + } + return field1.type.acceptCompareTo(field2.type, this); } @Override - public void visitDexMethod(DexMethod method1, DexMethod method2) { - if (stillEqual()) { - method1.holder.acceptCompareTo(method2.holder, this); - if (stillEqual()) { - namingLens.lookupName(method1).acceptCompareTo(namingLens.lookupName(method2), this); - if (stillEqual()) { - method1.proto.acceptCompareTo(method2.proto, this); - } - } + public int visitDexMethod(DexMethod method1, DexMethod method2) { + int order = method1.holder.acceptCompareTo(method2.holder, this); + if (order != 0) { + return order; } + order = namingLens.lookupName(method1).acceptCompareTo(namingLens.lookupName(method2), this); + if (order != 0) { + return order; + } + return method1.proto.acceptCompareTo(method2.proto, this); } }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java index dfd9fa0..78fb663 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java +++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java
@@ -4,20 +4,11 @@ package com.android.tools.r8.utils.structural; import com.android.tools.r8.graph.DexString; -import com.android.tools.r8.graph.NamingLensComparable; import com.android.tools.r8.naming.NamingLens; import java.util.function.ToIntFunction; public class CompareToVisitorWithStringTable extends CompareToVisitorWithNamingLens { - public static <T extends NamingLensComparable<T>> int run( - T item1, T item2, NamingLens namingLens, ToIntFunction<DexString> stringTable) { - CompareToVisitorWithNamingLens state = - new CompareToVisitorWithStringTable(namingLens, stringTable); - item1.acceptCompareTo(item2, state); - return state.getOrder(); - } - private final ToIntFunction<DexString> stringTable; public CompareToVisitorWithStringTable( @@ -27,9 +18,7 @@ } @Override - public void visitDexString(DexString string1, DexString string2) { - if (stillEqual()) { - visitInt(stringTable.applyAsInt(string1), stringTable.applyAsInt(string2)); - } + public int visitDexString(DexString string1, DexString string2) { + return visitInt(stringTable.applyAsInt(string1), stringTable.applyAsInt(string2)); } }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java index 62b1942..89bd02b 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java +++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java
@@ -8,15 +8,14 @@ public class CompareToVisitorWithTypeEquivalence extends CompareToVisitorBase { - public static <T> int run(T item1, T item2, RepresentativeMap map, StructuralAccept<T> visit) { + public static <T> int run(T item1, T item2, RepresentativeMap map, StructuralMapping<T> visit) { return run(item1, item2, map, (i1, i2, visitor) -> visitor.visit(i1, i2, visit)); } public static <T> int run( T item1, T item2, RepresentativeMap map, CompareToAccept<T> compareToAccept) { CompareToVisitorWithTypeEquivalence state = new CompareToVisitorWithTypeEquivalence(map); - compareToAccept.acceptCompareTo(item1, item2, state); - return state.getOrder(); + return compareToAccept.acceptCompareTo(item1, item2, state); } private final RepresentativeMap representatives; @@ -26,11 +25,9 @@ } @Override - public void visitDexType(DexType type1, DexType type2) { - if (stillEqual()) { - DexType repr1 = representatives.getRepresentative(type1); - DexType repr2 = representatives.getRepresentative(type2); - repr1.getDescriptor().acceptCompareTo(repr2.getDescriptor(), this); - } + public int visitDexType(DexType type1, DexType type2) { + DexType repr1 = representatives.getRepresentative(type1); + DexType repr2 = representatives.getRepresentative(type2); + return repr1.getDescriptor().acceptCompareTo(repr2.getDescriptor(), this); } }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java index 94fb1f9..52a718a 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java +++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java
@@ -5,24 +5,11 @@ import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.NamingLensComparable; import com.android.tools.r8.naming.NamingLens; import java.util.function.ToIntFunction; public class CompareToVisitorWithTypeTable extends CompareToVisitorWithStringTable { - public static <T extends NamingLensComparable<T>> int run( - T item1, - T item2, - NamingLens namingLens, - ToIntFunction<DexString> stringTable, - ToIntFunction<DexType> typeTable) { - CompareToVisitorWithNamingLens state = - new CompareToVisitorWithTypeTable(namingLens, stringTable, typeTable); - item1.acceptCompareTo(item2, state); - return state.getOrder(); - } - private final ToIntFunction<DexType> typeTable; public CompareToVisitorWithTypeTable( @@ -34,9 +21,7 @@ } @Override - public void visitDexType(DexType type1, DexType type2) { - if (stillEqual()) { - visitInt(typeTable.applyAsInt(type1), typeTable.applyAsInt(type2)); - } + public int visitDexType(DexType type1, DexType type2) { + return visitInt(typeTable.applyAsInt(type1), typeTable.applyAsInt(type2)); } }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/DefaultCompareToVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/DefaultCompareToVisitor.java index 9f91d19..aa3fd96 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/DefaultCompareToVisitor.java +++ b/src/main/java/com/android/tools/r8/utils/structural/DefaultCompareToVisitor.java
@@ -13,7 +13,7 @@ */ public class DefaultCompareToVisitor { - public static <T> int run(T item1, T item2, StructuralAccept<T> visit) { + public static <T> int run(T item1, T item2, StructuralMapping<T> visit) { return run(item1, item2, (i1, i2, visitor) -> visitor.visit(i1, i2, visit)); }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/DefaultHashingVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/DefaultHashingVisitor.java index 2ec503c..d1b6653 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/DefaultHashingVisitor.java +++ b/src/main/java/com/android/tools/r8/utils/structural/DefaultHashingVisitor.java
@@ -14,7 +14,7 @@ */ public class DefaultHashingVisitor { - public static <T> void run(T item, Hasher hasher, StructuralAccept<T> accept) { + public static <T> void run(T item, Hasher hasher, StructuralMapping<T> accept) { run(item, hasher, (i, visitor) -> visitor.visit(i, accept)); }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java index 1b5b400..c64e0b8 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java +++ b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
@@ -23,7 +23,7 @@ */ public class HashCodeVisitor<T> extends StructuralSpecification<T, HashCodeVisitor<T>> { - public static <T> int run(T item, StructuralAccept<T> visit) { + public static <T> int run(T item, StructuralMapping<T> visit) { HashCodeVisitor<T> visitor = new HashCodeVisitor<>(item); visit.apply(visitor); return visitor.hashCode;
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java index ed0f61e..696c454 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java +++ b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java
@@ -43,18 +43,18 @@ public abstract void visitDexType(DexType type); public void visitDexField(DexField field) { - visit(field, field.getStructuralAccept()); + visit(field, field.getStructuralMapping()); } public void visitDexMethod(DexMethod method) { - visit(method, method.getStructuralAccept()); + visit(method, method.getStructuralMapping()); } public void visitDexReference(DexReference reference) { reference.accept(this::visitDexType, this::visitDexField, this::visitDexMethod); } - public abstract <S> void visit(S item, StructuralAccept<S> accept); + public abstract <S> void visit(S item, StructuralMapping<S> accept); @Deprecated public abstract <S> void visit(S item, BiConsumer<S, Hasher> hasher);
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java index 63989f5..ba499a3 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java +++ b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
@@ -20,7 +20,7 @@ public class HashingVisitorWithTypeEquivalence extends HashingVisitor { public static <T> void run( - T item, Hasher hasher, RepresentativeMap map, StructuralAccept<T> accept) { + T item, Hasher hasher, RepresentativeMap map, StructuralMapping<T> accept) { run(item, hasher, map, (i, visitor) -> visitor.visit(i, accept)); } @@ -73,7 +73,7 @@ } @Override - public <S> void visit(S item, StructuralAccept<S> accept) { + public <S> void visit(S item, StructuralMapping<S> accept) { accept.apply(new ItemSpecification<>(item, this)); }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/StructuralItem.java b/src/main/java/com/android/tools/r8/utils/structural/StructuralItem.java index 92542f2..8740299 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/StructuralItem.java +++ b/src/main/java/com/android/tools/r8/utils/structural/StructuralItem.java
@@ -11,13 +11,13 @@ T self(); - StructuralAccept<T> getStructuralAccept(); + StructuralMapping<T> getStructuralMapping(); // CompareTo implementation and callbacks. @FunctionalInterface interface CompareToAccept<T> { - void acceptCompareTo(T item1, T item2, CompareToVisitor visitor); + int acceptCompareTo(T item1, T item2, CompareToVisitor visitor); } /** @@ -43,8 +43,8 @@ } /** Default accept for compareTo visitors. Override to change behavior. */ - default void acceptCompareTo(T other, CompareToVisitor visitor) { - visitor.visit(self(), other, self().getStructuralAccept()); + default int acceptCompareTo(T other, CompareToVisitor visitor) { + return visitor.visit(self(), other, self().getStructuralMapping()); } // Hashing implemenation and callbacks. @@ -61,7 +61,7 @@ * ensure that the effect is in place for any HashingVisitor. */ default void hash(Hasher hasher) { - DefaultHashingVisitor.run(self(), hasher, self().getStructuralAccept()); + DefaultHashingVisitor.run(self(), hasher, StructuralItem::acceptHashing); } /** Hashing method to use from tests to avoid having guava types shared between R8 and tests. */ @@ -78,11 +78,11 @@ * ensure that the effect is in place for any HashingVisitor. */ default void hashWithTypeEquivalence(Hasher hasher, RepresentativeMap map) { - HashingVisitorWithTypeEquivalence.run(self(), hasher, map, self().getStructuralAccept()); + HashingVisitorWithTypeEquivalence.run(self(), hasher, map, StructuralItem::acceptHashing); } /** Default accept for hashing visitors. Override to change behavior. */ default void acceptHashing(HashingVisitor visitor) { - visitor.visit(self(), self().getStructuralAccept()); + visitor.visit(self(), self().getStructuralMapping()); } }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/StructuralAccept.java b/src/main/java/com/android/tools/r8/utils/structural/StructuralMapping.java similarity index 71% rename from src/main/java/com/android/tools/r8/utils/structural/StructuralAccept.java rename to src/main/java/com/android/tools/r8/utils/structural/StructuralMapping.java index ede348f..b9e6bc2 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/StructuralAccept.java +++ b/src/main/java/com/android/tools/r8/utils/structural/StructuralMapping.java
@@ -4,9 +4,7 @@ package com.android.tools.r8.utils.structural; /** Mapping of a specification over an item. */ -// TODO(b/171867022): Rename this to StructuralMapping to avoid confusion with the Acceptor and -// accept classes. @FunctionalInterface -public interface StructuralAccept<T> { +public interface StructuralMapping<T> { void apply(StructuralSpecification<T, ?> spec); }
diff --git a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java index ff74111..891fbd7 100644 --- a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java +++ b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
@@ -66,18 +66,23 @@ public final <S extends StructuralItem<S>> V withConditionalItem( Predicate<T> predicate, Function<T, S> getter) { - return withConditionalCustomItem(predicate, getter, S::acceptCompareTo, S::acceptHashing); + return withConditionalCustomItem( + predicate, getter, StructuralItem::acceptCompareTo, StructuralItem::acceptHashing); } public final <S extends StructuralItem<S>> V withItemCollection( Function<T, Collection<S>> getter) { return withItemIterator( - getter.andThen(Collection::iterator), S::acceptCompareTo, S::acceptHashing); + getter.andThen(Collection::iterator), + StructuralItem::acceptCompareTo, + StructuralItem::acceptHashing); } public final <S extends StructuralItem<S>> V withItemArray(Function<T, S[]> getter) { return withItemIterator( - getter.andThen(a -> Arrays.asList(a).iterator()), S::acceptCompareTo, S::acceptHashing); + getter.andThen(a -> Arrays.asList(a).iterator()), + StructuralItem::acceptCompareTo, + StructuralItem::acceptHashing); } /**
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java index a8b5af7..5669af0 100644 --- a/src/test/java/com/android/tools/r8/TestBase.java +++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -17,6 +17,7 @@ import com.android.tools.r8.ToolHelper.DexVm; import com.android.tools.r8.ToolHelper.KotlinTargetVersion; import com.android.tools.r8.ToolHelper.ProcessResult; +import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.code.Instruction; import com.android.tools.r8.dex.ApplicationReader; import com.android.tools.r8.errors.Unreachable; @@ -1724,4 +1725,35 @@ .compile() .writeToZip(); } + + protected static CfVersion extractClassFileVersion(byte[] classFileBytes) { + class ClassFileVersionExtractor extends ClassVisitor { + private int version; + + private ClassFileVersionExtractor() { + super(ASM_VERSION); + } + + @Override + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) { + this.version = version; + } + + CfVersion getClassFileVersion() { + return CfVersion.fromRaw(version); + } + } + + ClassReader reader = new ClassReader(classFileBytes); + ClassFileVersionExtractor extractor = new ClassFileVersionExtractor(); + reader.accept( + extractor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + return extractor.getClassFileVersion(); + } }
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java index 625a3dc..7e8c85c 100644 --- a/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java +++ b/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java
@@ -76,6 +76,7 @@ : transformer(MainDump.dump(), Reference.classFromClass(Main.class)) .stripFrames("main") .transform()) + .addOptionsModification(options -> options.testing.readInputStackMaps = true) .setMinApi(parameters.getApiLevel()) .compileWithExpectedDiagnostics(this::verifyWarningsRegardingStackMap) .run(parameters.getRuntime(), Main.class) @@ -94,6 +95,7 @@ .addKeepMainRule(Main.class) .setMinApi(parameters.getApiLevel()) .allowDiagnosticWarningMessages(!includeFrameInHandler) + .addOptionsModification(options -> options.testing.readInputStackMaps = true) .compileWithExpectedDiagnostics(this::verifyWarningsRegardingStackMap) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest.java new file mode 100644 index 0000000..e552c0a --- /dev/null +++ b/src/test/java/com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest.java
@@ -0,0 +1,177 @@ +// Copyright (c) 2020, 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.cf.stackmap; + +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import java.io.IOException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +@RunWith(Parameterized.class) +public class SwitchStackFrameFallThroughTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public SwitchStackFrameFallThroughTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + testForJvm() + .addProgramClassFileData(SwitchStackFrameFallThroughTest$MainDump.dump()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("java.io.IOException"); + } + + @Test + public void testD8() throws Exception { + assumeTrue(parameters.isDexRuntime()); + testForD8(parameters.getBackend()) + .addProgramClassFileData(SwitchStackFrameFallThroughTest$MainDump.dump()) + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(options -> options.testing.readInputStackMaps = true) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("java.io.IOException"); + } + + public static class Main { + + public static void main(String[] args) { + Throwable throwable = null; + switch (args.length) { + case 0: + throwable = new IOException(); + break; + case 1: + throwable = new RuntimeException(); + break; + } + System.out.println(throwable.toString()); + } + } + + // The above is roughly the code that below, except we move the switch targets above the switch + // and then jump over them. We do this to check the fall-through of the switch. + public static class SwitchStackFrameFallThroughTest$MainDump implements Opcodes { + + public static byte[] dump() { + + ClassWriter classWriter = new ClassWriter(0); + MethodVisitor methodVisitor; + + classWriter.visit( + V1_8, + ACC_PUBLIC | ACC_SUPER, + "com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest$Main", + null, + "java/lang/Object", + null); + + classWriter.visitSource("SwitchStackFrameFallThroughTest.java", null); + + classWriter.visitInnerClass( + "com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest$Main", + "com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest", + "Main", + ACC_PUBLIC | ACC_STATIC); + + { + methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); + methodVisitor.visitCode(); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); + methodVisitor.visitInsn(RETURN); + methodVisitor.visitMaxs(1, 1); + methodVisitor.visitEnd(); + } + { + methodVisitor = + classWriter.visitMethod( + ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); + methodVisitor.visitCode(); + // This is moved here without a jump. + + Label label0 = new Label(); + Label label1 = new Label(); + Label label2 = new Label(); + Label label3 = new Label(); + + methodVisitor.visitJumpInsn(GOTO, label2); + + methodVisitor.visitLabel(label0); + methodVisitor.visitFrame( + Opcodes.F_FULL, + 1, + new Object[] {"[Ljava/lang/String;"}, + 1, + new Object[] {Opcodes.NULL}); + methodVisitor.visitInsn(POP); + methodVisitor.visitTypeInsn(NEW, "java/io/IOException"); + methodVisitor.visitInsn(DUP); + methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/io/IOException", "<init>", "()V", false); + methodVisitor.visitVarInsn(ASTORE, 1); + methodVisitor.visitJumpInsn(GOTO, label3); + + methodVisitor.visitLabel(label1); + methodVisitor.visitFrame( + Opcodes.F_FULL, + 1, + new Object[] {"[Ljava/lang/String;"}, + 1, + new Object[] {Opcodes.NULL}); + methodVisitor.visitInsn(POP); + methodVisitor.visitTypeInsn(NEW, "java/lang/RuntimeException"); + methodVisitor.visitInsn(DUP); + methodVisitor.visitMethodInsn( + INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "()V", false); + methodVisitor.visitVarInsn(ASTORE, 1); + methodVisitor.visitJumpInsn(GOTO, label3); + + methodVisitor.visitLabel(label2); + methodVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] {"[Ljava/lang/String;"}, 0, null); + methodVisitor.visitInsn(ACONST_NULL); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitInsn(ARRAYLENGTH); + methodVisitor.visitLookupSwitchInsn(label1, new int[] {0, 1}, new Label[] {label0, label1}); + methodVisitor.visitLabel(label3); + methodVisitor.visitFrame( + Opcodes.F_FULL, + 2, + new Object[] {"[Ljava/lang/String;", "java/lang/Throwable"}, + 0, + null); + methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + methodVisitor.visitVarInsn(ALOAD, 1); + methodVisitor.visitMethodInsn( + INVOKEVIRTUAL, "java/lang/Throwable", "toString", "()Ljava/lang/String;", false); + methodVisitor.visitMethodInsn( + INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); + methodVisitor.visitInsn(RETURN); + methodVisitor.visitMaxs(4, 2); + methodVisitor.visitEnd(); + } + classWriter.visitEnd(); + + return classWriter.toByteArray(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java index 3ae4175..c43c289 100644 --- a/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java +++ b/src/test/java/com/android/tools/r8/cfmethodgeneration/MethodGenerationBase.java
@@ -94,6 +94,7 @@ private void readMethodTemplatesInto(CfCodePrinter codePrinter) throws IOException { InternalOptions options = new InternalOptions(); + options.testing.readInputStackMaps = true; JarClassFileReader reader = new JarClassFileReader( new JarApplicationReader(options),
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java index 49437ff..6b50afe 100644 --- a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java +++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java
@@ -50,18 +50,11 @@ .writeToZip(); if (parameters.getRuntime().isCf()) { - // Run on the JVM given that Cf version is supported. - if (cfVersion <= parameters.getRuntime().asCf().getVm().getClassfileVersion()) { - testForJvm() - .addProgramFiles(jar) - .run(parameters.getRuntime(), TestClass.class) - .assertSuccessWithOutputLines("Hello, world!"); - } else { - testForJvm() - .addProgramFiles(jar) - .run(parameters.getRuntime(), TestClass.class) - .assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class); - } + // Run on the JVM given that Cf version is supported. When we desugar we now target 1.7 (51). + testForJvm() + .addProgramFiles(jar) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines("Hello, world!"); } else { assert parameters.getRuntime().isDex(); // Convert to DEX without desugaring.
diff --git a/src/test/java/com/android/tools/r8/desugaring/DesugarCfVersion.java b/src/test/java/com/android/tools/r8/desugaring/DesugarCfVersion.java new file mode 100644 index 0000000..493fe3d --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugaring/DesugarCfVersion.java
@@ -0,0 +1,256 @@ +// Copyright (c) 2020, 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.desugaring; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.cf.CfVersion; +import com.android.tools.r8.utils.ZipUtils; +import com.google.common.io.ByteStreams; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class DesugarCfVersion extends TestBase { + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withCfRuntimes().withAllApiLevelsAlsoForCf().build(); + } + + public DesugarCfVersion(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void test() throws Exception { + Path zip1 = + testForD8(parameters.getBackend()) + .addProgramClassFileData(hide_1_8) + .setMinApi(parameters.getApiLevel()) + .compile() + .writeToZip(); + + Path zip2 = + testForD8(parameters.getBackend()) + .addProgramClassFileData(hide_1_7) + .setMinApi(parameters.getApiLevel()) + .compile() + .writeToZip(); + + boolean canUseStaticAndDefaultInterfaceMethods = + parameters + .getApiLevel() + .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport()); + byte[] bytes1 = ByteStreams.toByteArray(Files.newInputStream(zip1)); + byte[] bytes2 = ByteStreams.toByteArray(Files.newInputStream(zip2)); + if (!canUseStaticAndDefaultInterfaceMethods) { + assertArrayEquals(bytes1, bytes2); + } + + assertEquals(CfVersion.V1_8, extractClassFileVersion(hide_1_8)); + assertEquals(CfVersion.V1_7, extractClassFileVersion(hide_1_7)); + assertEquals( + canUseStaticAndDefaultInterfaceMethods ? CfVersion.V1_8 : CfVersion.V1_7, + extractClassFileVersion( + ZipUtils.readSingleEntry(zip1, "com/google/android/gms/common/internal/Hide.class"))); + assertEquals( + CfVersion.V1_7, + extractClassFileVersion( + ZipUtils.readSingleEntry(zip2, "com/google/android/gms/common/internal/Hide.class"))); + } + + /* + Class file bytes for: + + public interface com.google.android.gms.common.internal.Hide extends java.lang.annotation.Annotation + minor version: 0 + major version: 52 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #1 // com/google/android/gms/common/internal/Hide + super_class: #2 // java/lang/Object + interfaces: 1, fields: 0, methods: 0, attributes: 2 + Constant pool: + #1 = Class #19 // com/google/android/gms/common/internal/Hide + #2 = Class #20 // java/lang/Object + #3 = Class #21 // java/lang/annotation/Annotation + #4 = Utf8 SourceFile + #5 = Utf8 Hide.java + #6 = Utf8 RuntimeVisibleAnnotations + #7 = Utf8 Ljava/lang/annotation/Target; + #8 = Utf8 value + #9 = Utf8 Ljava/lang/annotation/ElementType; + #10 = Utf8 TYPE + #11 = Utf8 FIELD + #12 = Utf8 METHOD + #13 = Utf8 CONSTRUCTOR + #14 = Utf8 PACKAGE + #15 = Utf8 Ljava/lang/annotation/Retention; + #16 = Utf8 Ljava/lang/annotation/RetentionPolicy; + #17 = Utf8 CLASS + #18 = Utf8 Ljava/lang/annotation/Documented; + #19 = Utf8 com/google/android/gms/common/internal/Hide + #20 = Utf8 java/lang/Object + #21 = Utf8 java/lang/annotation/Annotation + { + } + SourceFile: "Hide.java" + RuntimeVisibleAnnotations: + 0: #7(#8=[e#9.#10,e#9.#11,e#9.#12,e#9.#13,e#9.#14]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR,Ljava/lang/annotation/ElementType;.PACKAGE] + ) + 1: #15(#8=e#16.#17) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) + 2: #18() + java.lang.annotation.Documented + + */ + + private static byte[] hide_1_8 = + new byte[] { + -54, -2, -70, -66, 0, 0, 0, 52, 0, 22, 7, 0, 19, 7, 0, 20, + 7, 0, 21, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, + 1, 0, 9, 72, 105, 100, 101, 46, 106, 97, 118, 97, 1, 0, 25, 82, + 117, 110, 116, 105, 109, 101, 86, 105, 115, 105, 98, 108, 101, 65, 110, 110, + 111, 116, 97, 116, 105, 111, 110, 115, 1, 0, 29, 76, 106, 97, 118, 97, + 47, 108, 97, 110, 103, 47, 97, 110, 110, 111, 116, 97, 116, 105, 111, 110, + 47, 84, 97, 114, 103, 101, 116, 59, 1, 0, 5, 118, 97, 108, 117, 101, + 1, 0, 34, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 97, 110, + 110, 111, 116, 97, 116, 105, 111, 110, 47, 69, 108, 101, 109, 101, 110, 116, + 84, 121, 112, 101, 59, 1, 0, 4, 84, 89, 80, 69, 1, 0, 5, 70, + 73, 69, 76, 68, 1, 0, 6, 77, 69, 84, 72, 79, 68, 1, 0, 11, + 67, 79, 78, 83, 84, 82, 85, 67, 84, 79, 82, 1, 0, 7, 80, 65, + 67, 75, 65, 71, 69, 1, 0, 32, 76, 106, 97, 118, 97, 47, 108, 97, + 110, 103, 47, 97, 110, 110, 111, 116, 97, 116, 105, 111, 110, 47, 82, 101, + 116, 101, 110, 116, 105, 111, 110, 59, 1, 0, 38, 76, 106, 97, 118, 97, + 47, 108, 97, 110, 103, 47, 97, 110, 110, 111, 116, 97, 116, 105, 111, 110, + 47, 82, 101, 116, 101, 110, 116, 105, 111, 110, 80, 111, 108, 105, 99, 121, + 59, 1, 0, 5, 67, 76, 65, 83, 83, 1, 0, 33, 76, 106, 97, 118, + 97, 47, 108, 97, 110, 103, 47, 97, 110, 110, 111, 116, 97, 116, 105, 111, + 110, 47, 68, 111, 99, 117, 109, 101, 110, 116, 101, 100, 59, 1, 0, 43, + 99, 111, 109, 47, 103, 111, 111, 103, 108, 101, 47, 97, 110, 100, 114, 111, + 105, 100, 47, 103, 109, 115, 47, 99, 111, 109, 109, 111, 110, 47, 105, 110, + 116, 101, 114, 110, 97, 108, 47, 72, 105, 100, 101, 1, 0, 16, 106, 97, + 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, + 31, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 97, 110, 110, 111, 116, + 97, 116, 105, 111, 110, 47, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, + 38, 1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 0, 0, 0, 0, 2, + 0, 4, 0, 0, 0, 2, 0, 5, 0, 6, 0, 0, 0, 51, 0, 3, + 0, 7, 0, 1, 0, 8, 91, 0, 5, 101, 0, 9, 0, 10, 101, 0, + 9, 0, 11, 101, 0, 9, 0, 12, 101, 0, 9, 0, 13, 101, 0, 9, + 0, 14, 0, 15, 0, 1, 0, 8, 101, 0, 16, 0, 17, 0, 18, 0, + 0 + }; + + /* + Class file bytes for: + + public interface com.google.android.gms.common.internal.Hide extends java.lang.annotation.Annotation + minor version: 0 + major version: 51 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #2 // com/google/android/gms/common/internal/Hide + super_class: #4 // java/lang/Object + interfaces: 1, fields: 0, methods: 0, attributes: 2 + Constant pool: + #1 = Utf8 com/google/android/gms/common/internal/Hide + #2 = Class #1 // com/google/android/gms/common/internal/Hide + #3 = Utf8 java/lang/Object + #4 = Class #3 // java/lang/Object + #5 = Utf8 java/lang/annotation/Annotation + #6 = Class #5 // java/lang/annotation/Annotation + #7 = Utf8 Hide.java + #8 = Utf8 Ljava/lang/annotation/Target; + #9 = Utf8 value + #10 = Utf8 Ljava/lang/annotation/ElementType; + #11 = Utf8 TYPE + #12 = Utf8 FIELD + #13 = Utf8 METHOD + #14 = Utf8 CONSTRUCTOR + #15 = Utf8 PACKAGE + #16 = Utf8 Ljava/lang/annotation/Retention; + #17 = Utf8 Ljava/lang/annotation/RetentionPolicy; + #18 = Utf8 CLASS + #19 = Utf8 Ljava/lang/annotation/Documented; + #20 = Utf8 SourceFile + #21 = Utf8 RuntimeVisibleAnnotations + { + } + SourceFile: "Hide.java" + RuntimeVisibleAnnotations: + 0: #8(#9=[e#10.#11,e#10.#12,e#10.#13,e#10.#14,e#10.#15]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR,Ljava/lang/annotation/ElementType;.PACKAGE] + ) + 1: #16(#9=e#17.#18) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) + 2: #19() + java.lang.annotation.Documented + + */ + private static byte[] hide_1_7 = + new byte[] { + -54, -2, -70, -66, 0, 0, 0, 51, 0, 22, 1, 0, 43, 99, 111, 109, + 47, 103, 111, 111, 103, 108, 101, 47, 97, 110, 100, 114, 111, 105, 100, 47, + 103, 109, 115, 47, 99, 111, 109, 109, 111, 110, 47, 105, 110, 116, 101, 114, + 110, 97, 108, 47, 72, 105, 100, 101, 7, 0, 1, 1, 0, 16, 106, 97, + 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 7, 0, + 3, 1, 0, 31, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 97, 110, + 110, 111, 116, 97, 116, 105, 111, 110, 47, 65, 110, 110, 111, 116, 97, 116, + 105, 111, 110, 7, 0, 5, 1, 0, 9, 72, 105, 100, 101, 46, 106, 97, + 118, 97, 1, 0, 29, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, + 97, 110, 110, 111, 116, 97, 116, 105, 111, 110, 47, 84, 97, 114, 103, 101, + 116, 59, 1, 0, 5, 118, 97, 108, 117, 101, 1, 0, 34, 76, 106, 97, + 118, 97, 47, 108, 97, 110, 103, 47, 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 47, 69, 108, 101, 109, 101, 110, 116, 84, 121, 112, 101, 59, 1, + 0, 4, 84, 89, 80, 69, 1, 0, 5, 70, 73, 69, 76, 68, 1, 0, + 6, 77, 69, 84, 72, 79, 68, 1, 0, 11, 67, 79, 78, 83, 84, 82, + 85, 67, 84, 79, 82, 1, 0, 7, 80, 65, 67, 75, 65, 71, 69, 1, + 0, 32, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 97, 110, 110, + 111, 116, 97, 116, 105, 111, 110, 47, 82, 101, 116, 101, 110, 116, 105, 111, + 110, 59, 1, 0, 38, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, + 97, 110, 110, 111, 116, 97, 116, 105, 111, 110, 47, 82, 101, 116, 101, 110, + 116, 105, 111, 110, 80, 111, 108, 105, 99, 121, 59, 1, 0, 5, 67, 76, + 65, 83, 83, 1, 0, 33, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, + 47, 97, 110, 110, 111, 116, 97, 116, 105, 111, 110, 47, 68, 111, 99, 117, + 109, 101, 110, 116, 101, 100, 59, 1, 0, 10, 83, 111, 117, 114, 99, 101, + 70, 105, 108, 101, 1, 0, 25, 82, 117, 110, 116, 105, 109, 101, 86, 105, + 115, 105, 98, 108, 101, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 115, + 38, 1, 0, 2, 0, 4, 0, 1, 0, 6, 0, 0, 0, 0, 0, 2, + 0, 20, 0, 0, 0, 2, 0, 7, 0, 21, 0, 0, 0, 51, 0, 3, + 0, 8, 0, 1, 0, 9, 91, 0, 5, 101, 0, 10, 0, 11, 101, 0, + 10, 0, 12, 101, 0, 10, 0, 13, 101, 0, 10, 0, 14, 101, 0, 10, + 0, 15, 0, 16, 0, 1, 0, 9, 101, 0, 17, 0, 18, 0, 19, 0, + 0 + }; + + // Code for generating the lists above. + public static void main(String[] args) throws IOException { + Path file = Paths.get(args[0]); + byte[] content = ByteStreams.toByteArray(Files.newInputStream(file)); + final int bytesPerLine = 16; + for (int i = 0; i < content.length; i += bytesPerLine) { + for (int j = 0; j < bytesPerLine && i + j < content.length; j++) { + System.out.print(content[i + j] + ", "); + } + System.out.println(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java new file mode 100644 index 0000000..bef0cd5 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java
@@ -0,0 +1,116 @@ +// Copyright (c) 2020, 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.devirtualize; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.NoVerticalClassMerging; +import com.android.tools.r8.R8TestRunResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.MethodSubject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +// This is a reproduction of b/173812804. +@RunWith(Parameterized.class) +public class PrivateOverridePublicizerDevirtualizerTest extends TestBase { + + private final TestParameters parameters; + private final String[] EXPECTED = new String[] {"A::foo", "B::foo"}; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public PrivateOverridePublicizerDevirtualizerTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testRuntime() throws Exception { + testForRuntime(parameters) + .addInnerClasses(PrivateOverridePublicizerDevirtualizerTest.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED); + } + + @Test + public void testR8() throws Exception { + R8TestRunResult runResult = + testForR8(parameters.getBackend()) + .addInnerClasses(PrivateOverridePublicizerDevirtualizerTest.class) + .enableInliningAnnotations() + .enableNoVerticalClassMergingAnnotations() + .enableNeverClassInliningAnnotations() + .addKeepMainRule(Main.class) + .allowAccessModification() + .noMinification() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect( + inspector -> { + ClassSubject classA = inspector.clazz(A.class); + assertThat(classA, isPresent()); + MethodSubject fooA = classA.uniqueMethodWithName("foo"); + // TODO(b/173812804): This should not be removed. + assertThat(fooA, not(isPresent())); + }) + .run(parameters.getRuntime(), Main.class); + if (parameters.isDexRuntime()) { + // TODO(b/173812804): This should not fail verification + runResult.assertFailureWithErrorThatThrows(VerifyError.class); + } else { + // TODO(b/173812804): This should have been A::foo, B::foo. + runResult.assertSuccessWithOutputLines("B::foo", "B::foo"); + } + } + + @NeverClassInline + @NoVerticalClassMerging + public static class A { + @NeverInline + private void foo() { + System.out.println("A::foo"); // <-- this is made public by the publicizer + } + + public void callFoo() { + foo(); + } + } + + @NeverClassInline + public static class B extends A { + @NeverInline + private void foo() { + System.out.println("B::foo"); + } + + @Override + @NeverInline + public void callFoo() { + // We end up inlining A::callFoo, and then, because the call to A::foo is public, we end up + // target B::foo in the virtualizer. + super.callFoo(); + foo(); + } + } + + public static class Main { + + public static void main(String[] args) { + new B().callFoo(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/fields/FieldAnalysisTest.java b/src/test/java/com/android/tools/r8/ir/optimize/fields/FieldAnalysisTest.java new file mode 100644 index 0000000..4089f0e --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/fields/FieldAnalysisTest.java
@@ -0,0 +1,118 @@ +// Copyright (c) 2020, 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.fields; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.StringUtils; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class FieldAnalysisTest extends TestBase { + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static List<Object[]> data() { + return buildParameters(getTestParameters().withAllRuntimesAndApiLevels().build()); + } + + public FieldAnalysisTest(TestParameters parameters) { + this.parameters = parameters; + } + + private static String EXPECTED_RESULT = StringUtils.lines("42", "7", "21", "42", "49", "28"); + + @Test + public void testD8AndJava() throws Exception { + testForRuntime(parameters.getRuntime(), parameters.getApiLevel()) + .addInnerClasses(FieldAnalysisTest.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED_RESULT); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .setMinApi(parameters.getApiLevel()) + .addInnerClasses(FieldAnalysisTest.class) + .addKeepMainRule(Main.class) + .enableInliningAnnotations() + .enableNeverClassInliningAnnotations() + .compile() + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutput(EXPECTED_RESULT); + } + + @NeverClassInline + static class A { + int f = 42; + + @NeverInline + A() {} + + @NeverInline + A(int f) { + this.f = f; + } + } + + @NeverClassInline + static class B extends A { + @NeverInline + B() { + super(); + } + + @NeverInline + B(int f) { + this(); + this.f = f; + } + + @NeverInline + B(int unused, int f) { + super(unused); + this.f = f; + } + } + + @NeverClassInline + static class C extends A { + @NeverInline + C() { + super(); + } + + @NeverInline + C(int f) { + this(); + this.f = f + this.f; + } + + @NeverInline + C(int unused, int f) { + super(unused); + this.f = f + this.f; + } + } + + static class Main { + public static void main(String[] args) { + System.out.println(new B().f); + System.out.println(new B(7).f); + System.out.println(new B(7, 21).f); + + System.out.println(new C().f); + System.out.println(new C(7).f); + System.out.println(new C(7, 21).f); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapInvalidInitTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapInvalidInitTest.java new file mode 100644 index 0000000..c8d8086 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapInvalidInitTest.java
@@ -0,0 +1,113 @@ +// Copyright (c) 2020, 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.switches; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class SwitchMapInvalidInitTest extends TestBase { + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withDexRuntimes().withAllApiLevels().build(); + } + + public SwitchMapInvalidInitTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testInvalidInitSwitchMap() throws Exception { + testForR8(parameters.getBackend()) + .addKeepMainRule(Main.class) + .enableInliningAnnotations() + .addInnerClasses(SwitchMapInvalidInitTest.class) + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect(this::assertNoSwitchMap) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("init", "init", "init", "a", "b", "a", "b"); + } + + private void assertNoSwitchMap(CodeInspector codeInspector) { + // Main and the 2 enum classes. + assertEquals(3, codeInspector.allClasses().size()); + assertThat(codeInspector.clazz(Main.class), isPresent()); + assertThat(codeInspector.clazz(MyEnum1.class), isPresent()); + assertThat(codeInspector.clazz(MyEnum2.class), isPresent()); + } + + @NeverClassInline + enum MyEnum1 { + // The System call cannot be traced, therefore enum field can be read before being set. + A(System.currentTimeMillis()), + B(0), + C(1); + private final long time; + + MyEnum1(long time) { + this.time = time; + } + } + + @NeverClassInline + enum MyEnum2 { + A, + B, + C; + + MyEnum2() { + // The System call cannot be traced, therefore any enum field can be read before being set. + System.out.println("init"); + } + } + + public static class Main { + public static void main(String[] args) { + switch2(MyEnum2.A); + switch2(MyEnum2.B); + switch2(MyEnum2.C); + switch1(MyEnum1.A); + switch1(MyEnum1.B); + switch1(MyEnum1.C); + } + + @NeverInline + private static void switch1(MyEnum1 e) { + switch (e) { + case A: + System.out.println("a"); + break; + case B: + System.out.println("b"); + break; + } + } + + @NeverInline + private static void switch2(MyEnum2 e) { + switch (e) { + case A: + System.out.println("a"); + break; + case B: + System.out.println("b"); + break; + } + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithEnumDependencyTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithEnumDependencyTest.java new file mode 100644 index 0000000..14d5f18 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithEnumDependencyTest.java
@@ -0,0 +1,89 @@ +// Copyright (c) 2020, 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.switches; + +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.R8TestCompileResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +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 SwitchMapWithEnumDependencyTest extends TestBase { + + private final TestParameters parameters; + private static final String[] EXPECTED_RESULT = {"AD", "SB", "BE", "SC", "CF"}; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public SwitchMapWithEnumDependencyTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void test() throws Exception { + R8TestCompileResult compile = + testForR8(parameters.getBackend()) + .addInnerClasses(SwitchMapWithEnumDependencyTest.class) + .addKeepMainRule(TestClass.class) + .noMinification() + .enableInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile(); + compile + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines(EXPECTED_RESULT); + } + + static class TestClass { + public static void main(String[] args) { + switchMethod(); + } + + @NeverInline + private static void switchMethod() { + for (MyEnum value : MyEnum.values()) { + switch (value) { + case B: + System.out.println("SB"); + break; + case C: + System.out.println("SC"); + break; + } + System.out.println(value.toString()); + } + } + } + + enum MyEnum { + A(MyEnumDependency.D), + B(MyEnumDependency.E), + C(MyEnumDependency.F); + + final MyEnumDependency dependency; + + MyEnum(MyEnumDependency dependency) { + this.dependency = dependency; + } + + @Override + public String toString() { + return super.toString() + dependency.toString(); + } + } + + enum MyEnumDependency { + D, + E, + F + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithSubtypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithSubtypesTest.java new file mode 100644 index 0000000..7bc82e8 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithSubtypesTest.java
@@ -0,0 +1,124 @@ +// Copyright (c) 2020, 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.switches; + +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.R8TestCompileResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +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 SwitchMapWithSubtypesTest extends TestBase { + + private final TestParameters parameters; + private static final String[] EXPECTED_RESULT = { + "ta", "SB", "tb", "SC", "C", "D", "tatrue", "SB", "tbtrue", "SC", "Cfalse", "Dfalse" + }; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public SwitchMapWithSubtypesTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void test() throws Exception { + R8TestCompileResult compile = + testForR8(parameters.getBackend()) + .addInnerClasses(SwitchMapWithSubtypesTest.class) + .addKeepMainRule(TestClass.class) + .noMinification() + .enableInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile(); + compile + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines(EXPECTED_RESULT); + } + + static class TestClass { + public static void main(String[] args) { + switchMethod(); + switchMethodSubtype(); + } + + @NeverInline + private static void switchMethod() { + for (MyEnum value : MyEnum.values()) { + switch (value) { + case B: + System.out.println("SB"); + break; + case C: + System.out.println("SC"); + break; + } + System.out.println(value.toString()); + } + } + + @NeverInline + private static void switchMethodSubtype() { + for (MyEnumSubtype value : MyEnumSubtype.values()) { + switch (value) { + case B: + System.out.println("SB"); + break; + case C: + System.out.println("SC"); + break; + } + System.out.println(value.toString() + value.subType); + } + } + } + + enum MyEnum { + A { + @Override + public String toString() { + return "ta"; + } + }, + B { + @Override + public String toString() { + return "tb"; + } + }, + C, + D; + } + + enum MyEnumSubtype { + A(true) { + @Override + public String toString() { + return "ta"; + } + }, + B(true) { + @Override + public String toString() { + return "tb"; + } + }, + C(false), + D(false); + + final boolean subType; + + MyEnumSubtype(boolean fieldSet) { + this.subType = fieldSet; + } + } +}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryMethodTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryMethodTest.java index 9eefd15..58155cc 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryMethodTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryMethodTest.java
@@ -4,10 +4,11 @@ package com.android.tools.r8.repackage; +import static org.hamcrest.MatcherAssert.assertThat; + import com.android.tools.r8.NeverInline; -import com.android.tools.r8.R8TestRunResult; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.ToolHelper.DexVm.Version; +import com.android.tools.r8.utils.codeinspector.CodeInspector; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -34,23 +35,23 @@ @Test public void testR8() throws Exception { - R8TestRunResult runResult = - testForR8(parameters.getBackend()) - .addLibraryClasses(Library.class) - .addDefaultRuntimeLibrary(parameters) - .addProgramClasses(Program.class, Main.class) - .apply(this::configureRepackaging) - .addKeepMainRule(Main.class) - .enableInliningAnnotations() - .setMinApi(parameters.getApiLevel()) - .compile() - .addRunClasspathFiles(buildOnDexRuntime(parameters, Library.class)) - .run(parameters.getRuntime(), Main.class); - if (parameters.isDexRuntime() && parameters.getDexRuntimeVersion() == Version.V8_1_0) { - runResult.assertSuccessWithOutputLines(EXPECTED); - } else { - runResult.assertFailureWithErrorThatThrows(IllegalAccessError.class); - } + testForR8(parameters.getBackend()) + .addLibraryClasses(Library.class) + .addDefaultRuntimeLibrary(parameters) + .addProgramClasses(Program.class, Main.class) + .apply(this::configureRepackaging) + .addKeepMainRule(Main.class) + .enableInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile() + .addRunClasspathFiles(buildOnDexRuntime(parameters, Library.class)) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED) + .inspect(this::inspect); + } + + private void inspect(CodeInspector inspector) { + assertThat(Program.class, isNotRepackaged(inspector)); } public static class Library {
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryOverrideTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryOverrideTest.java index 7773fef..ce1c039 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryOverrideTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryOverrideTest.java
@@ -4,9 +4,11 @@ package com.android.tools.r8.repackage; +import static org.hamcrest.MatcherAssert.assertThat; + import com.android.tools.r8.NeverClassInline; -import com.android.tools.r8.R8TestRunResult; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.codeinspector.CodeInspector; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -33,23 +35,23 @@ @Test public void testR8() throws Exception { - R8TestRunResult runResult = - testForR8(parameters.getBackend()) - .addLibraryClasses(Library.class) - .addDefaultRuntimeLibrary(parameters) - .addProgramClasses(Program.class, Main.class) - .apply(this::configureRepackaging) - .addKeepMainRule(Main.class) - .setMinApi(parameters.getApiLevel()) - .enableNeverClassInliningAnnotations() - .compile() - .addRunClasspathFiles(buildOnDexRuntime(parameters, Library.class)) - .run(parameters.getRuntime(), Main.class); - if (parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik()) { - runResult.assertSuccessWithOutputLines(EXPECTED); - } else { - runResult.assertSuccessWithOutputLines("Library::foo"); - } + testForR8(parameters.getBackend()) + .addLibraryClasses(Library.class) + .addDefaultRuntimeLibrary(parameters) + .addProgramClasses(Program.class, Main.class) + .apply(this::configureRepackaging) + .addKeepMainRule(Main.class) + .setMinApi(parameters.getApiLevel()) + .enableNeverClassInliningAnnotations() + .compile() + .addRunClasspathFiles(buildOnDexRuntime(parameters, Library.class)) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED) + .inspect(this::inspect); + } + + private void inspect(CodeInspector inspector) { + assertThat(Program.class, isNotRepackaged(inspector)); } public static class Library {
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryTypeTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryTypeTest.java index 1a35ded..90939fb 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryTypeTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithPackagePrivateLibraryTypeTest.java
@@ -4,9 +4,12 @@ package com.android.tools.r8.repackage; +import static org.hamcrest.MatcherAssert.assertThat; + import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.codeinspector.CodeInspector; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -49,7 +52,13 @@ .setMinApi(parameters.getApiLevel()) .addRunClasspathFiles(buildOnDexRuntime(parameters, Library.class, LibraryI.class)) .run(parameters.getRuntime(), Main.class) - .assertFailureWithErrorThatThrows(IllegalAccessError.class); + .assertSuccessWithOutputLines(EXPECTED) + .inspect(this::inspect); + } + + private void inspect(CodeInspector inspector) { + assertThat(Program.class, isNotRepackaged(inspector)); + assertThat(ProgramSub.class, isNotRepackaged(inspector)); } static class Library {}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java index 0d99817..37dbe19 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
@@ -47,7 +47,8 @@ } public HorizontallyMergedClassesInspector assertClassNotMerged(Class<?> clazz) { - assertFalse(horizontallyMergedClasses.hasBeenMerged(toDexType(clazz, dexItemFactory))); + assertFalse( + horizontallyMergedClasses.hasBeenMergedIntoDifferentType(toDexType(clazz, dexItemFactory))); return this; }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java index 421b54a..619b415 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java
@@ -27,7 +27,9 @@ } public HorizontallyMergedLambdaClassesInspector assertMerged(Class<?> clazz) { - assertTrue(horizontallyMergedLambdaClasses.hasBeenMerged(toDexType(clazz, dexItemFactory))); + assertTrue( + horizontallyMergedLambdaClasses.hasBeenMergedIntoDifferentType( + toDexType(clazz, dexItemFactory))); return this; } @@ -39,7 +41,9 @@ } public HorizontallyMergedLambdaClassesInspector assertClassNotMerged(Class<?> clazz) { - assertFalse(horizontallyMergedLambdaClasses.hasBeenMerged(toDexType(clazz, dexItemFactory))); + assertFalse( + horizontallyMergedLambdaClasses.hasBeenMergedIntoDifferentType( + toDexType(clazz, dexItemFactory))); return this; }
diff --git a/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsCustomOrderTest.java b/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsCustomOrderTest.java index cfea69c..679200c 100644 --- a/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsCustomOrderTest.java +++ b/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsCustomOrderTest.java
@@ -98,7 +98,7 @@ private final int x; private final B b; - private static void accept(StructuralSpecification<A, ?> spec) { + private static void specify(StructuralSpecification<A, ?> spec) { spec.withInt(a -> a.x).withItem(a -> a.b); } @@ -108,8 +108,8 @@ } @Override - public StructuralAccept<A> getStructuralAccept() { - return A::accept; + public StructuralMapping<A> getStructuralMapping() { + return A::specify; } @Override @@ -124,7 +124,7 @@ @Override public final int hashCode() { - return HashCodeVisitor.run(this, A::accept); + return HashCodeVisitor.run(this, A::specify); } } @@ -132,7 +132,7 @@ private final int y; - private static void accept(StructuralSpecification<B, ?> spec) { + private static void specify(StructuralSpecification<B, ?> spec) { spec.withInt(b -> b.y); } @@ -141,8 +141,8 @@ } @Override - public StructuralAccept<B> getStructuralAccept() { - return B::accept; + public StructuralMapping<B> getStructuralMapping() { + return B::specify; } @Override @@ -157,14 +157,14 @@ @Override public final int hashCode() { - return HashCodeVisitor.run(this, B::accept); + return HashCodeVisitor.run(this, B::specify); } // Override allowing a change to the order of any type of compare-to visitation, e.g., with // and without a type equivalence map. @Override - public void acceptCompareTo(B other, CompareToVisitor visitor) { - visitor.visit(other, this, B::accept); + public int acceptCompareTo(B other, CompareToVisitor visitor) { + return visitor.visit(other, this, B::specify); } } }
diff --git a/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsTest.java b/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsTest.java index 64481c3..b9580ed 100644 --- a/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsTest.java +++ b/src/test/java/com/android/tools/r8/utils/structural/StructuralItemsTest.java
@@ -117,7 +117,7 @@ private final int x; private final B b; - private static void accept(StructuralSpecification<A, ?> spec) { + private static void specify(StructuralSpecification<A, ?> spec) { spec.withInt(a -> a.x).withItem(a -> a.b); } @@ -127,8 +127,8 @@ } @Override - public StructuralAccept<A> getStructuralAccept() { - return A::accept; + public StructuralMapping<A> getStructuralMapping() { + return A::specify; } @Override @@ -143,7 +143,7 @@ @Override public int hashCode() { - return HashCodeVisitor.run(this, A::accept); + return HashCodeVisitor.run(this, A::specify); } } @@ -151,7 +151,7 @@ private final int y; - private static void accept(StructuralSpecification<B, ?> spec) { + private static void specify(StructuralSpecification<B, ?> spec) { spec.withInt(b -> b.y); } @@ -160,8 +160,8 @@ } @Override - public StructuralAccept<B> getStructuralAccept() { - return B::accept; + public StructuralMapping<B> getStructuralMapping() { + return B::specify; } @Override @@ -176,7 +176,7 @@ @Override public int hashCode() { - return HashCodeVisitor.run(this, B::accept); + return HashCodeVisitor.run(this, B::specify); } } }
diff --git a/tools/compiledump.py b/tools/compiledump.py index 5c818d6..ebf3371 100755 --- a/tools/compiledump.py +++ b/tools/compiledump.py
@@ -47,6 +47,11 @@ help='Path to an R8 jar.', default=None) parser.add_argument( + '-override', + help='Do not override any extracted dump in temp-dir', + default=False, + action='store_true') + parser.add_argument( '--nolib', help='Use the non-lib distribution (default uses the lib distribution)', default=False, @@ -168,7 +173,13 @@ return Dump(args.dump) dump_file = zipfile.ZipFile(os.path.abspath(args.dump), 'r') with utils.ChangedWorkingDirectory(temp): - dump_file.extractall() + if args.override or not os.path.isfile( + os.path.join(temp, 'proguard.config')): + print("Extracting into: %s" % temp) + dump_file.extractall() + if not os.path.isfile(os.path.join(temp, 'proguard.config')): + error("Did not extract into %s. Either the zip file is invalid or the " + "dump is missing files" % temp) return Dump(temp) def determine_build_properties(args, dump):
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py index 0ceb3b0b..0d48887 100755 --- a/tools/run_on_app_dump.py +++ b/tools/run_on_app_dump.py
@@ -319,8 +319,6 @@ 'url': 'https://github.com/chrisbanes/tivi', 'revision': '8e2ddd8fe2d343264a66aa1ef8acbd4cc587e8ce', 'folder': 'tivi', - # TODO(b/173974110): Enable recompilation. - 'skip_recompilation': True, }), App({ 'id': 'com.keylesspalace.tusky',