blob: cd7343c27c1f4379f1d66f401ce69f3967c9210c [file] [log] [blame]
// Copyright (c) 2022, 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.compilerapi.artprofiles;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.R8;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TextInputStream;
import com.android.tools.r8.TextOutputStream;
import com.android.tools.r8.compilerapi.CompilerApiTest;
import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
import com.android.tools.r8.compilerapi.artprofiles.ArtProfilesForRewritingApiTest.ApiTest.ArtProfileConsumerForTesting;
import com.android.tools.r8.compilerapi.mockdata.MockClass;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.art.ArtProfileBuilder;
import com.android.tools.r8.profile.art.ArtProfileClassRuleInfo;
import com.android.tools.r8.profile.art.ArtProfileConsumer;
import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfo;
import com.android.tools.r8.profile.art.ArtProfileProvider;
import com.android.tools.r8.profile.art.ArtProfileRuleConsumer;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.ThrowingBiConsumer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
public class ArtProfilesForRewritingApiTest extends CompilerApiTestRunner {
private static final int SOME_API_LEVEL = 24;
public ArtProfilesForRewritingApiTest(TestParameters parameters) {
super(parameters);
}
@Override
public Class<? extends CompilerApiTest> binaryTestClass() {
return ApiTest.class;
}
@Test
public void testD8() throws Exception {
ApiTest test = new ApiTest(ApiTest.PARAMETERS);
runTest(test::runD8);
}
@Test
public void testR8() throws Exception {
ApiTest test = new ApiTest(ApiTest.PARAMETERS);
runTest(test::runR8);
}
private void runTest(
ThrowingBiConsumer<ArtProfileConsumerForTesting, ArtProfileConsumerForTesting, Exception>
testRunner)
throws Exception {
ArtProfileConsumerForTesting apiArtProfileConsumer = new ArtProfileConsumerForTesting();
ArtProfileConsumerForTesting textualArtProfileConsumer = new ArtProfileConsumerForTesting();
testRunner.accept(apiArtProfileConsumer, textualArtProfileConsumer);
for (ArtProfileConsumerForTesting artProfileConsumer :
new ArtProfileConsumerForTesting[] {apiArtProfileConsumer, textualArtProfileConsumer}) {
assertTrue(artProfileConsumer.isFinished());
assertTrue(artProfileConsumer.isOutputStreamClosed());
assertEquals(ApiTest.textualArtProfileLines, artProfileConsumer.getResidualArtProfileRules());
assertEquals(
ApiTest.textualArtProfileLines,
artProfileConsumer.getResidualArtProfileRulesFromOutputStream());
}
}
public static class ApiTest extends CompilerApiTest {
static ClassReference mockClassReference = Reference.classFromClass(MockClass.class);
static MethodReference mockInitMethodReference =
Reference.method(mockClassReference, "<init>", Collections.emptyList(), null);
static MethodReference mockMainMethodReference =
Reference.method(
mockClassReference,
"main",
Collections.singletonList(Reference.classFromClass(String[].class)),
null);
static List<String> textualArtProfileLines =
Arrays.asList(
"Lcom/android/tools/r8/compilerapi/mockdata/MockClass;",
"PLcom/android/tools/r8/compilerapi/mockdata/MockClass;-><init>()V",
"HSPLcom/android/tools/r8/compilerapi/mockdata/MockClass;->main([Ljava/lang/String;)V");
public ApiTest(Object parameters) {
super(parameters);
}
public void runD8(
ArtProfileConsumerForTesting apiArtProfileConsumer,
ArtProfileConsumerForTesting textualArtProfileConsumer)
throws Exception {
ApiArtProfileProviderForTesting apiArtProfileProvider = new ApiArtProfileProviderForTesting();
TextualArtProfileProviderForTesting textualArtProfileProvider =
new TextualArtProfileProviderForTesting();
D8Command.Builder commandBuilder =
D8Command.builder()
.addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
.addLibraryFiles(getJava8RuntimeJar())
.setMinApiLevel(SOME_API_LEVEL)
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
.addArtProfileForRewriting(apiArtProfileProvider, apiArtProfileConsumer)
.addArtProfileForRewriting(textualArtProfileProvider, textualArtProfileConsumer);
D8.run(commandBuilder.build());
assertTrue(textualArtProfileProvider.inputStream.isClosed());
}
public void runR8(
ArtProfileConsumerForTesting apiArtProfileConsumer,
ArtProfileConsumerForTesting textualArtProfileConsumer)
throws Exception {
ApiArtProfileProviderForTesting apiArtProfileProvider = new ApiArtProfileProviderForTesting();
TextualArtProfileProviderForTesting textualArtProfileProvider =
new TextualArtProfileProviderForTesting();
R8Command.Builder commandBuilder =
R8Command.builder()
.addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
.addProguardConfiguration(
Collections.singletonList("-keep class * { *; }"), Origin.unknown())
.addLibraryFiles(getJava8RuntimeJar())
.setMinApiLevel(SOME_API_LEVEL)
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
.addArtProfileForRewriting(apiArtProfileProvider, apiArtProfileConsumer)
.addArtProfileForRewriting(textualArtProfileProvider, textualArtProfileConsumer);
R8.run(commandBuilder.build());
assertTrue(textualArtProfileProvider.inputStream.isClosed());
}
@Test
public void testD8() throws Exception {
runD8(null, null);
}
@Test
public void testR8() throws Exception {
runR8(null, null);
}
static class ApiArtProfileProviderForTesting implements ArtProfileProvider {
@Override
public void getArtProfile(ArtProfileBuilder profileBuilder) {
profileBuilder
.addClassRule(
classRuleBuilder -> classRuleBuilder.setClassReference(mockClassReference))
.addMethodRule(
methodRuleBuilder ->
methodRuleBuilder
.setMethodReference(mockInitMethodReference)
.setMethodRuleInfo(
methodRuleInfoBuilder -> methodRuleInfoBuilder.setIsHot(true))
.setMethodRuleInfo(
methodRuleInfoBuilder -> methodRuleInfoBuilder.setIsPostStartup(true)))
.addMethodRule(
methodRuleBuilder ->
methodRuleBuilder
.setMethodReference(mockMainMethodReference)
.setMethodRuleInfo(
methodRuleInfoBuilder ->
methodRuleInfoBuilder
.setIsHot(true)
.setIsStartup(true)
.setIsPostStartup(true)));
}
@Override
public Origin getOrigin() {
return Origin.unknown();
}
}
static class TextualArtProfileProviderForTesting implements ArtProfileProvider {
final ClosableByteArrayInputStream inputStream =
new ClosableByteArrayInputStream(
String.join("\n", textualArtProfileLines).concat("\n").getBytes());
@Override
public void getArtProfile(ArtProfileBuilder profileBuilder) {
profileBuilder.addHumanReadableArtProfile(
new TextInputStream() {
@Override
public InputStream getInputStream() {
return inputStream;
}
@Override
public Charset getCharset() {
return StandardCharsets.UTF_8;
}
},
parserBuilderConsumer -> {});
}
@Override
public Origin getOrigin() {
return Origin.unknown();
}
}
static class ArtProfileConsumerForTesting implements ArtProfileConsumer {
private boolean finished;
private final List<String> residualArtProfileRules = new ArrayList<>();
private final ClosableByteArrayOutputStream outputStream =
new ClosableByteArrayOutputStream();
@Override
public TextOutputStream getHumanReadableArtProfileConsumer() {
return new TextOutputStream() {
@Override
public OutputStream getOutputStream() {
return outputStream;
}
@Override
public Charset getCharset() {
return StandardCharsets.UTF_8;
}
};
}
@Override
public ArtProfileRuleConsumer getRuleConsumer() {
return new ArtProfileRuleConsumer() {
@Override
public void acceptClassRule(
ClassReference classReference, ArtProfileClassRuleInfo classRuleInfo) {
residualArtProfileRules.add(classReference.getDescriptor());
}
@Override
public void acceptMethodRule(
MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) {
StringBuilder builder = new StringBuilder();
if (methodRuleInfo.isHot()) {
builder.append('H');
}
if (methodRuleInfo.isStartup()) {
builder.append('S');
}
if (methodRuleInfo.isPostStartup()) {
builder.append('P');
}
residualArtProfileRules.add(
builder
.append(methodReference.getHolderClass().getDescriptor())
.append("->")
.append(methodReference.getMethodName())
.append(methodReference.getMethodDescriptor())
.toString());
}
};
}
@Override
public void finished(DiagnosticsHandler handler) {
finished = true;
}
List<String> getResidualArtProfileRulesFromOutputStream()
throws UnsupportedEncodingException {
return Arrays.asList(outputStream.toString(StandardCharsets.UTF_8.name()).split("\n"));
}
List<String> getResidualArtProfileRules() {
return residualArtProfileRules;
}
boolean isFinished() {
return finished;
}
boolean isOutputStreamClosed() {
return outputStream.isClosed();
}
}
private static class ClosableByteArrayInputStream extends ByteArrayInputStream {
private boolean closed;
public ClosableByteArrayInputStream(byte[] buf) {
super(buf);
}
@Override
public void close() throws IOException {
super.close();
closed = true;
}
public boolean isClosed() {
return closed;
}
}
private static class ClosableByteArrayOutputStream extends ByteArrayOutputStream {
private boolean closed;
@Override
public void close() throws IOException {
super.close();
closed = true;
}
public boolean isClosed() {
return closed;
}
}
}
}