Version 2.0.86
Cherry-pick: Collect desugared library types used in check-cast and instanceof
CL: https://r8-review.googlesource.com/c/r8/+/52140
Cherry-pick: Collect desugared library exception types used in try/catch
CL: https://r8-review.googlesource.com/c/r8/+/52124
Cherry-pick: Provide access to try/catch guards in code inspector
CL: https://r8-review.googlesource.com/c/r8/+/52123
Bug: 158417777
Change-Id: I72052bed4e17abb4a01d25e8181bbcbca7b3a13b
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index bc4c231..80f3b35 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "2.0.85";
+ public static final String LABEL = "2.0.86";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/code/CheckCast.java b/src/main/java/com/android/tools/r8/code/CheckCast.java
index 57151fa..f472800 100644
--- a/src/main/java/com/android/tools/r8/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/code/CheckCast.java
@@ -38,6 +38,11 @@
}
@Override
+ public CheckCast asCheckCast() {
+ return this;
+ }
+
+ @Override
public boolean isCheckCast() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/code/InstanceOf.java b/src/main/java/com/android/tools/r8/code/InstanceOf.java
index 11b2d5c..4550406 100644
--- a/src/main/java/com/android/tools/r8/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/code/InstanceOf.java
@@ -23,6 +23,16 @@
}
@Override
+ public InstanceOf asInstanceOf() {
+ return this;
+ }
+
+ @Override
+ public boolean isInstanceOf() {
+ return true;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index d549e28..0d1aa9c 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -123,10 +123,22 @@
this.offset = offset;
}
+ public CheckCast asCheckCast() {
+ return null;
+ }
+
public boolean isCheckCast() {
return false;
}
+ public InstanceOf asInstanceOf() {
+ return null;
+ }
+
+ public boolean isInstanceOf() {
+ return false;
+ }
+
public ConstString asConstString() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
index ef1b81b..037d769 100644
--- a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
+++ b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
@@ -112,6 +112,10 @@
desugaredLibraryCodeToKeep.recordMethod(method);
} else if (insn.isConstClass()) {
desugaredLibraryCodeToKeep.recordClass(insn.asConstClass().getType());
+ } else if (insn.isInstanceOf()) {
+ desugaredLibraryCodeToKeep.recordClass(insn.asInstanceOf().getType());
+ } else if (insn.isCheckCast()) {
+ desugaredLibraryCodeToKeep.recordClass(insn.asCheckCast().getType());
}
insn.write(shortBuffer, mapping);
}
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 5cbd975..42f2065 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -507,6 +507,7 @@
for (TypeAddrPair pair : handler.pairs) {
dest.putUleb128(mapping.getOffsetFor(pair.type));
dest.putUleb128(pair.addr);
+ desugaredLibraryCodeToKeep.recordClass(pair.type);
}
if (hasCatchAll) {
dest.putUleb128(handler.catchAllAddr);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index 732c0b9..bb51ec7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -6,17 +6,25 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CheckCastInstructionSubject;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
-import java.util.Iterator;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TryCatchSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import com.google.common.collect.ImmutableSet;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -27,7 +35,8 @@
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
- private static final String expectedOutput = StringUtils.lines("Hello, world");
+ private static final String expectedOutput =
+ StringUtils.lines("Caught java.time.format.DateTimeParseException", "Hello, world");
@Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
public static List<Object[]> data() {
@@ -41,15 +50,50 @@
}
private void checkRewrittenInvokes(CodeInspector inspector) {
+ Set<String> expectedInvokeHolders;
+ Set<String> expectedCatchGuards;
+ Set<String> expectedCheckCastType;
+ String expectedInstanceOfTypes;
if (parameters.getApiLevel().getLevel() >= 26) {
- return;
+ expectedInvokeHolders = ImmutableSet.of("java.time.Clock", "java.time.LocalDate");
+ expectedCatchGuards = ImmutableSet.of("java.time.format.DateTimeParseException");
+ expectedCheckCastType = ImmutableSet.of("java.time.ZoneId");
+ expectedInstanceOfTypes = "java.time.ZoneOffset";
+ } else {
+ expectedInvokeHolders = ImmutableSet.of("j$.time.Clock", "j$.time.LocalDate");
+ expectedCatchGuards = ImmutableSet.of("j$.time.format.DateTimeParseException");
+ expectedCheckCastType = ImmutableSet.of("j$.time.ZoneId");
+ expectedInstanceOfTypes = "j$.time.ZoneOffset";
}
ClassSubject classSubject = inspector.clazz(TestClass.class);
assertThat(classSubject, isPresent());
- Iterator<InvokeInstructionSubject> iterator =
- classSubject.uniqueMethodWithName("main").iterateInstructions(InstructionSubject::isInvoke);
- InvokeInstructionSubject invoke = iterator.next();
- assertTrue(invoke.holder().is("j$.time.Clock"));
+ MethodSubject main = classSubject.uniqueMethodWithName("main");
+ Set<String> foundInvokeHolders =
+ main.streamInstructions()
+ .filter(InstructionSubject::isInvoke)
+ .map(
+ instructionSubject ->
+ ((InvokeInstructionSubject) instructionSubject).holder().toString())
+ .filter(holder -> holder.startsWith("j$.time.") || holder.startsWith("java.time."))
+ .collect(Collectors.toSet());
+ assertEquals(expectedInvokeHolders, foundInvokeHolders);
+ main.streamInstructions()
+ .filter(InstructionSubject::isCheckCast)
+ .map(InstructionSubject::asCheckCast)
+ .map(CheckCastInstructionSubject::getType)
+ .map(DexType::toSourceString)
+ .collect(Collectors.toSet())
+ .equals(expectedCheckCastType);
+ assertEquals(
+ 1,
+ main.streamInstructions().filter(io -> io.isInstanceOf(expectedInstanceOfTypes)).count());
+
+ Set<String> foundCatchGuards =
+ main.streamTryCatches()
+ .flatMap(TryCatchSubject::streamGuards)
+ .map(TypeSubject::toString)
+ .collect(Collectors.toSet());
+ assertEquals(expectedCatchGuards, foundCatchGuards);
}
@Test
@@ -78,6 +122,7 @@
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .enableInliningAnnotations()
.compile()
.inspect(this::checkRewrittenInvokes)
.addDesugaredCoreLibraryRunClassPath(
@@ -91,8 +136,27 @@
static class TestClass {
+ @NeverInline
+ public static Object newObjectInstance() {
+ return System.currentTimeMillis() > 0 ? new Object() : null;
+ }
+
+ @NeverInline
+ public static Object nullReference() {
+ return System.currentTimeMillis() > 0 ? null : new Object();
+ }
+
public static void main(String[] args) {
java.time.Clock.systemDefaultZone();
+ try {
+ java.time.LocalDate.parse("");
+ } catch (java.time.format.DateTimeParseException e) {
+ System.out.println("Caught java.time.format.DateTimeParseException");
+ }
+ java.time.ZoneId id = (java.time.ZoneId) nullReference();
+ if (newObjectInstance() instanceof java.time.ZoneOffset) {
+ System.out.println("NOT!");
+ }
System.out.println("Hello, world");
}
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java
index 663a070..edbf072 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java
@@ -11,12 +11,17 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
class CfTryCatchSubject implements TryCatchSubject {
+ private final CodeInspector inspector;
private final CfCode cfCode;
private final CfTryCatch tryCatch;
- CfTryCatchSubject(CfCode cfCode, CfTryCatch tryCatch) {
+ CfTryCatchSubject(CodeInspector inspector, CfCode cfCode, CfTryCatch tryCatch) {
+ this.inspector = inspector;
this.cfCode = cfCode;
this.tryCatch = tryCatch;
}
@@ -61,4 +66,13 @@
return isCatching(DexItemFactory.throwableDescriptorString);
}
+ @Override
+ public Stream<TypeSubject> streamGuards() {
+ return tryCatch.guards.stream().map(type -> new TypeSubject(inspector, type));
+ }
+
+ @Override
+ public Collection<TypeSubject> guards() {
+ return streamGuards().collect(Collectors.toList());
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 757216c..a628af9 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -391,11 +391,11 @@
}
TryCatchSubject createTryCatchSubject(DexCode code, Try tryElement, TryHandler tryHandler) {
- return new DexTryCatchSubject(code, tryElement, tryHandler);
+ return new DexTryCatchSubject(this, code, tryElement, tryHandler);
}
TryCatchSubject createTryCatchSubject(CfCode code, CfTryCatch tryCatch) {
- return new CfTryCatchSubject(code, tryCatch);
+ return new CfTryCatchSubject(this, code, tryCatch);
}
TryCatchIterator createTryCatchIterator(MethodSubject method) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java
index ed46590..e6ba14f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java
@@ -9,13 +9,20 @@
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
class DexTryCatchSubject implements TryCatchSubject {
+ private final CodeInspector inspector;
private final DexCode dexCode;
private final Try tryElement;
private final TryHandler tryHandler;
- DexTryCatchSubject(DexCode dexCode, Try tryElement, TryHandler tryHandler) {
+ DexTryCatchSubject(
+ CodeInspector inspector, DexCode dexCode, Try tryElement, TryHandler tryHandler) {
+ this.inspector = inspector;
this.dexCode = dexCode;
this.tryElement = tryElement;
this.tryHandler = tryHandler;
@@ -44,4 +51,15 @@
return tryHandler.catchAllAddr != NO_HANDLER;
}
+ @Override
+ public Stream<TypeSubject> streamGuards() {
+ return Arrays.stream(tryHandler.pairs)
+ .map(pair -> pair.type)
+ .map(type -> new TypeSubject(inspector, type));
+ }
+
+ @Override
+ public Collection<TypeSubject> guards() {
+ return streamGuards().collect(Collectors.toList());
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index af6e1a4..62f0682 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -86,6 +86,10 @@
return Streams.stream(iterateInstructions());
}
+ public Stream<TryCatchSubject> streamTryCatches() {
+ return Streams.stream(iterateTryCatches());
+ }
+
public void getLineNumberForInstruction(InstructionSubject subject) {
assert hasLineNumberTable();
getLineNumberTable().getLineForInstruction(subject);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java
index 838f7a8..993ab7e 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java
@@ -3,8 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.codeinspector;
+import java.util.Collection;
+import java.util.stream.Stream;
+
public interface TryCatchSubject {
RangeSubject getRange();
boolean isCatching(String exceptionType);
boolean hasCatchAll();
+
+ Stream<TypeSubject> streamGuards();
+
+ Collection<TypeSubject> guards();
}