Check dexing of j$ jar does not modify descriptors
Change-Id: I42c92156b7baf5482272e80f567a11b1e76d770c
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index e2c826a..bd0152e 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -100,6 +100,7 @@
private boolean minimalMainDex = false;
private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
private boolean enableMissingLibraryApiModeling = false;
+ private boolean enableRewritingOfArtProfilesIsNopCheck = false;
private Builder() {
this(new DefaultD8DiagnosticsHandler());
@@ -410,6 +411,11 @@
return self();
}
+ Builder setEnableRewritingOfArtProfilesIsNopCheck() {
+ enableRewritingOfArtProfilesIsNopCheck = true;
+ return self();
+ }
+
@Override
void validate() {
if (isPrintHelp()) {
@@ -523,6 +529,7 @@
proguardMapConsumer,
partitionMapConsumer,
enableMissingLibraryApiModeling,
+ enableRewritingOfArtProfilesIsNopCheck,
getAndroidPlatformBuild(),
getArtProfilesForRewriting(),
getStartupProfileProviders(),
@@ -545,6 +552,7 @@
private final StringConsumer proguardMapConsumer;
private final PartitionMapConsumer partitionMapConsumer;
private final boolean enableMissingLibraryApiModeling;
+ private final boolean enableRewritingOfArtProfilesIsNopCheck;
private final DexItemFactory factory;
public static Builder builder() {
@@ -621,6 +629,7 @@
StringConsumer proguardMapConsumer,
PartitionMapConsumer partitionMapConsumer,
boolean enableMissingLibraryApiModeling,
+ boolean enableRewritingOfArtProfilesIsNopCheck,
boolean isAndroidPlatformBuild,
List<ArtProfileForRewriting> artProfilesForRewriting,
List<StartupProfileProvider> startupProfileProviders,
@@ -662,6 +671,7 @@
this.proguardMapConsumer = proguardMapConsumer;
this.partitionMapConsumer = partitionMapConsumer;
this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
+ this.enableRewritingOfArtProfilesIsNopCheck = enableRewritingOfArtProfilesIsNopCheck;
this.factory = factory;
}
@@ -680,6 +690,7 @@
proguardMapConsumer = null;
partitionMapConsumer = null;
enableMissingLibraryApiModeling = false;
+ enableRewritingOfArtProfilesIsNopCheck = false;
factory = null;
}
@@ -751,6 +762,10 @@
internal.apiModelingOptions().disableOutliningAndStubbing();
}
+ if (enableRewritingOfArtProfilesIsNopCheck) {
+ internal.getArtProfileOptions().setEnableNopCheckForTesting();
+ }
+
// Default is to remove all javac generated assertion code when generating dex.
assert internal.assertionsConfiguration == null;
internal.assertionsConfiguration =
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index c471c33..679dd95 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -357,9 +357,13 @@
if (proguardMapConsumer != null || partitionMapConsumer != null) {
reporter.error("L8 does not support defining a map consumer when not shrinking");
}
- if (isGeneratingClassFiles && !getArtProfilesForRewriting().isEmpty()) {
- reporter.error(
- "L8 does not support rewriting of ART profiles when generating class files");
+ if (!getArtProfilesForRewriting().isEmpty()) {
+ if (isGeneratingClassFiles) {
+ reporter.error(
+ "L8 does not support rewriting of ART profiles when generating class files");
+ } else {
+ reporter.error("L8 does not impact ART profiles when generating DEX and not shrinking");
+ }
}
}
super.validate();
@@ -432,12 +436,8 @@
.setMode(getMode())
.setIncludeClassesChecksum(getIncludeClassesChecksum())
.setDexClassChecksumFilter(getDexClassChecksumFilter())
- .setProgramConsumer(getProgramConsumer());
- for (ArtProfileForRewriting artProfileForRewriting : getArtProfilesForRewriting()) {
- d8Builder.addArtProfileForRewriting(
- artProfileForRewriting.getArtProfileProvider(),
- artProfileForRewriting.getResidualArtProfileConsumer());
- }
+ .setProgramConsumer(getProgramConsumer())
+ .setEnableRewritingOfArtProfilesIsNopCheck();
for (ClassFileResourceProvider libraryResourceProvider :
inputs.getLibraryResourceProviders()) {
d8Builder.addLibraryResourceProvider(libraryResourceProvider);
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
index 2b2f387..e132aed 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
@@ -36,6 +36,9 @@
if (artProfileOptions.isCompletenessCheckForTestingEnabled()) {
artProfiles.add(createCompleteArtProfile(appInfo));
}
+ if (artProfileOptions.isNopCheckForTestingEnabled()) {
+ assert artProfileOptions.setNopCheckForTestingHashCode(appInfo);
+ }
if (artProfiles.isEmpty()) {
return empty();
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
index 4d60860..9e78975 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
@@ -6,8 +6,14 @@
import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyOrDefault;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
@@ -19,11 +25,14 @@
private Collection<ArtProfileForRewriting> artProfilesForRewriting = Collections.emptyList();
private boolean enableCompletenessCheckForTesting =
parseSystemPropertyOrDefault(COMPLETENESS_PROPERTY_KEY, false);
+ private boolean enableNopCheckForTesting;
private boolean hasReadArtProfileProviders = false;
private boolean allowReadingEmptyArtProfileProvidersMultipleTimesForTesting = false;
private final InternalOptions options;
+ private String nopCheckForTestingHashCode;
+
public ArtProfileOptions(InternalOptions options) {
this.options = options;
}
@@ -51,6 +60,10 @@
&& !options.getStartupInstrumentationOptions().isStartupInstrumentationEnabled();
}
+ public boolean isNopCheckForTestingEnabled() {
+ return enableNopCheckForTesting;
+ }
+
public boolean isIncludingApiReferenceStubs() {
// We only include API reference stubs in the residual ART profiles for completeness testing.
// This is because the API reference stubs should never be used at runtime except for
@@ -105,4 +118,35 @@
this.enableCompletenessCheckForTesting = enableCompletenessCheckForTesting;
return this;
}
+
+ public ArtProfileOptions setEnableNopCheckForTesting() {
+ this.enableNopCheckForTesting = true;
+ return this;
+ }
+
+ public boolean setNopCheckForTestingHashCode(AppInfo appInfo) {
+ if (nopCheckForTestingHashCode != null) {
+ String hashCode = computeNopCheckForTestingHashCode(appInfo);
+ assert hashCode.equals(nopCheckForTestingHashCode);
+ } else {
+ nopCheckForTestingHashCode = computeNopCheckForTestingHashCode(appInfo);
+ }
+ return true;
+ }
+
+ private static String computeNopCheckForTestingHashCode(AppInfo appInfo) {
+ Hasher hasher = Hashing.sha256().newHasher();
+ for (DexProgramClass clazz : appInfo.classesWithDeterministicOrder()) {
+ hasher.putString(clazz.getType().toDescriptorString(), StandardCharsets.UTF_8);
+ for (DexEncodedMethod method : clazz.methods()) {
+ hasher.putString(method.getReference().toSmaliString(), StandardCharsets.UTF_8);
+ }
+ }
+ return hasher.hash().toString();
+ }
+
+ public boolean verifyHasNopCheckForTestingHashCode() {
+ assert nopCheckForTestingHashCode != null;
+ return true;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
index bcf3221..a4b8450 100644
--- a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
@@ -69,7 +69,12 @@
@Override
public void supplyConsumers(AppView<?> appView) {
- if (appView.options().getArtProfileOptions().isCompletenessCheckForTestingEnabled()) {
+ ArtProfileOptions artProfileOptions = appView.options().getArtProfileOptions();
+ if (artProfileOptions.isNopCheckForTestingEnabled()) {
+ assert artProfileOptions.verifyHasNopCheckForTestingHashCode();
+ assert artProfileOptions.setNopCheckForTestingHashCode(appView.appInfo());
+ }
+ if (artProfileOptions.isCompletenessCheckForTestingEnabled()) {
assert ArtProfileCompletenessChecker.verify(appView);
ListUtils.removeLast(artProfiles);
if (artProfiles.isEmpty()) {
diff --git a/src/test/java/com/android/tools/r8/CommandTestBase.java b/src/test/java/com/android/tools/r8/CommandTestBase.java
index 886aeba..7a71837 100644
--- a/src/test/java/com/android/tools/r8/CommandTestBase.java
+++ b/src/test/java/com/android/tools/r8/CommandTestBase.java
@@ -26,6 +26,7 @@
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
@@ -321,9 +322,17 @@
FileUtils.writeTextFile(profile, profileRuleFlags + profileRuleDescriptor);
// Pass the profile on the command line.
+ List<String> args =
+ new ArrayList<>(
+ ImmutableList.of("--art-profile", profile.toString(), residualProfile.toString()));
+ // L8 only accepts an art profile when shrinking.
+ if (this instanceof L8CommandTest) {
+ Path path = temp.newFile("proguard-rules.pro").toPath();
+ FileUtils.writeTextFile(path, "-dontshrink");
+ args.addAll(ImmutableList.of("--pg-conf", path.toString()));
+ }
List<ArtProfileForRewriting> artProfilesForRewriting =
- parseWithRequiredArgs("--art-profile", profile.toString(), residualProfile.toString())
- .getArtProfilesForRewriting();
+ parseWithRequiredArgs(args.toArray(new String[0])).getArtProfilesForRewriting();
assertEquals(1, artProfilesForRewriting.size());
// Extract inputs.
diff --git a/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java
index b812f2d..811cb53 100644
--- a/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java
@@ -9,9 +9,13 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
@@ -21,6 +25,8 @@
import com.android.tools.r8.profile.art.utils.ArtProfileInspector;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AbortException;
+import com.android.tools.r8.utils.codeinspector.AssertUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -58,14 +64,28 @@
@Test
public void test() throws Throwable {
Assume.assumeTrue(libraryDesugaringSpecification.hasEmulatedInterfaceDesugaring(parameters));
- testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
- .addInnerClasses(getClass())
- .addKeepMainRule(Main.class)
- .addL8ArtProfileForRewriting(getArtProfile())
- .compile()
- .inspectL8ResidualArtProfile(this::inspect)
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("0");
+ AssertUtils.assertFailsCompilationIf(
+ !compilationSpecification.isL8Shrink(),
+ () ->
+ testForDesugaredLibrary(
+ parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addL8ArtProfileForRewriting(getArtProfile())
+ .compile()
+ .inspectL8ResidualArtProfile(this::inspect)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("0"),
+ exception -> {
+ assertEquals(CompilationFailedException.class, exception.getClass());
+ assertThat(exception.getMessage(), equalTo("Compilation failed to complete"));
+ assertNotNull(exception.getCause());
+ assertEquals(AbortException.class, exception.getCause().getClass());
+ assertThat(
+ exception.getCause().getMessage(),
+ containsString(
+ "L8 does not impact ART profiles when generating DEX and not shrinking"));
+ });
}
private ExternalArtProfile getArtProfile() {