blob: 7873c68f3b14f01dea2bd6b0d8de5c30bc6f711d [file] [log] [blame]
// Copyright (c) 2018, 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.outliner.b111893131;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.dex.code.DexInvokeVirtual;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
class TestClass {
public interface Act {
// Need both builder and arg to create code snippets for outline candidates.
String get(StringBuilder builder, String arg);
}
public static void main(String[] args) {
System.out.println(test(new TestClass("OK").toAct(), new StringBuilder(), "1"));
}
// Need to pass Act and call #get to create private instance lambda$
private static String test(Act act, StringBuilder builder, String arg) {
// Outline candidate
builder.append(arg).append(arg).append(arg);
act.get(builder, "#");
return builder.toString();
}
private final String foo;
TestClass(String foo) {
this.foo = foo;
}
private Act toAct() {
return (builder, arg) -> {
// Outline candidate
builder.append(arg).append(arg).append(arg);
return foo;
};
}
}
public class B111893131 extends TestBase {
@Test
public void test() throws Exception {
String javaResult = runOnJava(TestClass.class);
R8Command.Builder builder = R8Command.builder();
builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.Act.class));
builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
builder.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm().getLevel());
builder.setDisableMinification(true);
String config = keepMainProguardConfiguration(TestClass.class);
builder.addProguardConfiguration(ImmutableList.of(config), Origin.unknown());
AndroidApp app =
ToolHelper.runR8(
builder.build(),
options -> {
// To trigger outliner, set # of expected outline candidate as threshold.
options.outline.threshold = 2;
options.inlinerOptions().enableInlining = false;
options.enableStringConcatenationOptimization = false;
});
ProcessResult result = runOnArtRaw(app, TestClass.class);
assertEquals(result.toString(), 0, result.exitCode);
assertEquals(javaResult, result.stdout);
CodeInspector inspector = new CodeInspector(app);
ClassSubject classSubject = inspector.clazz(TestClass.class);
assertThat(classSubject, isPresent());
DexClass clazz = classSubject.getDexProgramClass();
clazz.forEachMethod(encodedMethod -> {
Code code = encodedMethod.getCode();
assertTrue(code.isDexCode());
DexCode dexCode = code.asDexCode();
verifyAbsenceOfStringBuilderAppend(dexCode.instructions);
});
}
private void verifyAbsenceOfStringBuilderAppend(DexInstruction[] instructions) {
for (DexInstruction instr : instructions) {
if (instr instanceof DexInvokeVirtual) {
DexInvokeVirtual invokeVirtual = (DexInvokeVirtual) instr;
DexMethod invokedMethod = invokeVirtual.getMethod();
if (invokedMethod.holder.getName().endsWith("StringBuilder")) {
assertNotEquals("append", invokedMethod.name.toString());
}
}
}
}
}