Allow comments and whitespace in ART profiles
Fixes: b/271160555
Change-Id: I1ce71acad9bea7c06261219ad35ec527481b7ecf
diff --git a/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java b/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java
index 85cca78..6c9ec51 100644
--- a/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java
+++ b/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java
@@ -50,9 +50,12 @@
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
int lineNumber = 1;
while (bufferedReader.ready()) {
- String rule = bufferedReader.readLine();
- if (!parseRule(rule)) {
- parseError(rule, lineNumber, origin);
+ String line = bufferedReader.readLine();
+ String lineWithoutComment = removeCommentFromLine(line);
+ if (isWhitespace(lineWithoutComment)) {
+ // Skip.
+ } else if (!parseRule(lineWithoutComment)) {
+ parseError(line, lineNumber, origin);
}
lineNumber++;
}
@@ -72,6 +75,15 @@
}
}
+ private boolean isWhitespace(String line) {
+ for (int i = 0; i < line.length(); i++) {
+ if (!Character.isWhitespace(line.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public boolean parseRule(String rule) {
try {
ArtProfileMethodRuleInfoImpl.Builder methodRuleInfoBuilder =
@@ -148,6 +160,14 @@
return true;
}
+ private static String removeCommentFromLine(String line) {
+ int commentStartIndex = line.indexOf('#');
+ if (commentStartIndex >= 0) {
+ return line.substring(0, commentStartIndex).stripTrailing();
+ }
+ return line;
+ }
+
public static class Builder implements HumanReadableArtProfileParserBuilder {
private Consumer<HumanReadableArtProfileParserErrorDiagnostic> diagnosticConsumer;
diff --git a/src/test/java/com/android/tools/r8/profile/art/format/ArtProfileWithCommentsAndWhitespaceTest.java b/src/test/java/com/android/tools/r8/profile/art/format/ArtProfileWithCommentsAndWhitespaceTest.java
new file mode 100644
index 0000000..834a5c1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/format/ArtProfileWithCommentsAndWhitespaceTest.java
@@ -0,0 +1,112 @@
+// Copyright (c) 2023, 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.profile.art.format;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.profile.art.ArtProfileBuilder;
+import com.android.tools.r8.profile.art.ArtProfileProvider;
+import com.android.tools.r8.profile.art.utils.ArtProfileInspector;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.UTF8TextInputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ArtProfileWithCommentsAndWhitespaceTest extends TestBase {
+
+ private static final MethodReference MAIN_METHOD_REFERENCE =
+ MethodReferenceUtils.mainMethod(Main.class);
+
+ private static Path profileWithComments;
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDefaultRuntimes().withMinimumApiLevel().build();
+ }
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ profileWithComments = getStaticTemp().newFile().toPath();
+ FileUtils.writeTextFile(
+ profileWithComments,
+ "# Comment 1",
+ " # Comment 2",
+ " ",
+ "\t",
+ "HSP" + MethodReferenceUtils.toSmaliString(MAIN_METHOD_REFERENCE),
+ "# Comment 3");
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ parameters.assumeDexRuntime();
+ testForD8()
+ .addProgramClasses(Main.class)
+ .addArtProfileForRewriting(getArtProfileProvider())
+ .release()
+ .setMinApi(parameters)
+ .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages)
+ .inspectResidualArtProfile(this::inspectResidualArtProfile);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class)
+ .addKeepMainRule(Main.class)
+ .addArtProfileForRewriting(getArtProfileProvider())
+ .setMinApi(parameters)
+ .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages)
+ .inspectResidualArtProfile(this::inspectResidualArtProfile);
+ }
+
+ private ArtProfileProvider getArtProfileProvider() {
+ return new ArtProfileProvider() {
+
+ @Override
+ public void getArtProfile(ArtProfileBuilder profileBuilder) {
+ try {
+ profileBuilder.addHumanReadableArtProfile(
+ new UTF8TextInputStream(profileWithComments), parserBuilder -> {});
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return new PathOrigin(profileWithComments);
+ }
+ };
+ }
+
+ private void inspectResidualArtProfile(ArtProfileInspector profileInspector) {
+ profileInspector.assertContainsMethodRule(MAIN_METHOD_REFERENCE).assertContainsNoOtherRules();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+ }
+}