blob: 1979d3481f761b40e859b86ed5a09f1b16f76cfb [file] [log] [blame]
// Copyright (c) 2021, 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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class OutlineMappingInformationTest extends TestBase {
private final TestParameters parameters;
private final boolean throwInFirstOutline;
private final boolean throwOnFirstCall;
@Parameterized.Parameters(name = "{0}, throwInFirstOutline: {1}, throwOnFirstCall: {2}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
BooleanUtils.values(),
BooleanUtils.values());
}
public OutlineMappingInformationTest(
TestParameters parameters, boolean throwInFirstOutline, boolean throwOnFirstCall) {
this.parameters = parameters;
this.throwInFirstOutline = throwInFirstOutline;
this.throwOnFirstCall = throwOnFirstCall;
}
StackTrace expectedStackTrace;
@Before
public void setup() throws Exception {
expectedStackTrace =
testForRuntime(parameters)
.addProgramClasses(TestClass.class, TestClass2.class, Greeter.class)
.run(
parameters.getRuntime(),
TestClass.class,
throwInFirstOutline ? "0" : "1",
throwOnFirstCall ? "0" : "1")
.assertFailureWithErrorThatThrows(ArrayStoreException.class)
.getStackTrace();
}
@Test
public void test() throws Exception {
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class, TestClass2.class, Greeter.class)
.addKeepMainRule(TestClass.class)
.addOptionsModification(
options -> {
options.outline.threshold = 2;
options.outline.minSize = 2;
})
.addKeepAttributeLineNumberTable()
.addKeepAttributeSourceFile()
.enableNoHorizontalClassMergingAnnotations()
.noHorizontalClassMergingOfSynthetics()
.addHorizontallyMergedClassesInspector(
HorizontallyMergedClassesInspector::assertNoClassesMerged)
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.run(
parameters.getRuntime(),
TestClass.class,
throwInFirstOutline ? "0" : "1",
throwOnFirstCall ? "0" : "1")
.assertFailureWithErrorThatThrows(ArrayStoreException.class)
.inspectStackTrace(
(stackTrace, inspector) -> {
// Two outlines are created, one for
// Greeter.throwExceptionFirst();
// Greeter.throwExceptionSecond();
// and one for
// new ArrayStoreException("Foo")
assertEquals(5, inspector.allClasses().size());
// TODO(b/201397823): Should always be equal.
if (throwInFirstOutline && !throwOnFirstCall) {
assertNotEquals(expectedStackTrace, stackTrace);
} else {
assertEquals(expectedStackTrace, stackTrace);
}
});
}
@NoHorizontalClassMerging
static class TestClass {
public static boolean shouldThrowInGreeter;
public static boolean throwOnFirst;
public static void main(String... args) {
shouldThrowInGreeter = args[0].equals("0");
throwOnFirst = args[1].equals("0");
greet();
shouldThrowInGreeter = true;
TestClass2.greet();
}
@NeverInline
static void greet() {
Greeter.throwExceptionFirst();
Greeter.throwExceptionSecond();
}
}
@NoHorizontalClassMerging
static class TestClass2 {
@NeverInline
static void greet() {
// Keep on same line
Greeter.throwExceptionFirst(); Greeter.throwExceptionSecond();
}
}
@NoHorizontalClassMerging
public static class Greeter {
@NeverInline
public static void throwExceptionFirst() {
if (TestClass.shouldThrowInGreeter && TestClass.throwOnFirst) {
throw new ArrayStoreException("Foo");
}
}
@NeverInline
public static void throwExceptionSecond() {
if (TestClass.shouldThrowInGreeter && !TestClass.throwOnFirst) {
throw new ArrayStoreException("Foo");
}
}
}
}