| // Copyright (c) 2020, 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.inliner.conditionalsimpleinlining; |
| |
| import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethodWithName; |
| import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; |
| import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; |
| import static org.hamcrest.CoreMatchers.not; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| |
| import com.android.tools.r8.NeverSingleCallerInline; |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.utils.BooleanUtils; |
| import com.android.tools.r8.utils.StringUtils; |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import com.android.tools.r8.utils.codeinspector.MethodSubject; |
| import com.google.common.collect.ImmutableList; |
| import java.util.List; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| @RunWith(Parameterized.class) |
| public class SimpleIfNullOrNotNullInliningTest extends ConditionalSimpleInliningTestBase { |
| |
| private final Class<?> mainClass; |
| |
| @Parameters(name = "{2}, main: {1}, simple inlining constraints: {0}") |
| public static List<Object[]> data() { |
| return buildParameters( |
| BooleanUtils.values(), |
| ImmutableList.of( |
| TestClassEligibleForSimpleInlining.class, TestClassIneligibleForSimpleInlining.class), |
| TestBase.getTestParameters().withAllRuntimesAndApiLevels().build()); |
| } |
| |
| public SimpleIfNullOrNotNullInliningTest( |
| boolean enableSimpleInliningConstraints, Class<?> mainClass, TestParameters parameters) { |
| super(enableSimpleInliningConstraints, parameters); |
| this.mainClass = mainClass; |
| } |
| |
| @Test |
| public void test() throws Exception { |
| testForR8(parameters.getBackend()) |
| .addProgramClasses(mainClass, TestMethods.class) |
| .addKeepMainRule(mainClass) |
| .apply(this::configure) |
| .enableNeverSingleCallerInlineAnnotations() |
| .compile() |
| .inspect(this::inspect) |
| .run(parameters.getRuntime(), mainClass) |
| .assertSuccessWithOutput(getExpectedOutput()); |
| } |
| |
| private String getExpectedOutput() { |
| if (mainClass == TestClassEligibleForSimpleInlining.class) { |
| return ""; |
| } |
| return StringUtils.times(StringUtils.lines("Hello world!"), 8); |
| } |
| |
| private void inspect(CodeInspector inspector) { |
| MethodSubject mainMethodSubject = inspector.clazz(mainClass).mainMethod(); |
| assertThat(mainMethodSubject, isPresent()); |
| assertThat(mainMethodSubject, not(invokesMethodWithName("print"))); |
| |
| ClassSubject classSubject = inspector.clazz(TestMethods.class); |
| assertThat(classSubject, notIf(isPresent(), shouldBeEligibleForSimpleInlining())); |
| |
| if (shouldBeEligibleForSimpleInlining()) { |
| return; |
| } |
| |
| assertThat(classSubject, isPresent()); |
| assertThat(classSubject.uniqueMethodWithName("simpleIfNullTest"), isPresent()); |
| assertThat(classSubject.uniqueMethodWithName("simpleIfBothNullTest"), isPresent()); |
| assertThat(classSubject.uniqueMethodWithName("simpleIfNotNullTest"), isPresent()); |
| assertThat(classSubject.uniqueMethodWithName("simpleIfBothNotNullTest"), isPresent()); |
| } |
| |
| private boolean shouldBeEligibleForSimpleInlining() { |
| return mainClass == TestClassEligibleForSimpleInlining.class && enableSimpleInliningConstraints; |
| } |
| |
| static class TestClassEligibleForSimpleInlining { |
| |
| public static void main(String[] args) { |
| Object notNull = new Object(); |
| TestMethods.simpleIfNullTest(null); |
| TestMethods.simpleIfBothNullTest(null, null); |
| TestMethods.simpleIfNotNullTest(notNull); |
| TestMethods.simpleIfBothNotNullTest(notNull, notNull); |
| } |
| } |
| |
| static class TestClassIneligibleForSimpleInlining { |
| |
| public static void main(String[] args) { |
| Object notNull = new Object(); |
| TestMethods.simpleIfNullTest(notNull); |
| TestMethods.simpleIfBothNullTest(null, notNull); |
| TestMethods.simpleIfBothNullTest(notNull, null); |
| TestMethods.simpleIfBothNullTest(notNull, notNull); |
| TestMethods.simpleIfNotNullTest(null); |
| TestMethods.simpleIfBothNotNullTest(null, notNull); |
| TestMethods.simpleIfBothNotNullTest(notNull, null); |
| TestMethods.simpleIfBothNotNullTest(null, null); |
| } |
| } |
| |
| static class TestMethods { |
| |
| @NeverSingleCallerInline |
| static void simpleIfNullTest(Object o) { |
| if (o == null) { |
| return; |
| } |
| System.out.print("H"); |
| System.out.print("e"); |
| System.out.print("l"); |
| System.out.print("l"); |
| System.out.print("o"); |
| System.out.print(" "); |
| System.out.print("w"); |
| System.out.print("o"); |
| System.out.print("r"); |
| System.out.print("l"); |
| System.out.print("d"); |
| System.out.println("!"); |
| } |
| |
| @NeverSingleCallerInline |
| static void simpleIfBothNullTest(Object o1, Object o2) { |
| if (o1 == null && o2 == null) { |
| return; |
| } |
| System.out.print("H"); |
| System.out.print("e"); |
| System.out.print("l"); |
| System.out.print("l"); |
| System.out.print("o"); |
| System.out.print(" "); |
| System.out.print("w"); |
| System.out.print("o"); |
| System.out.print("r"); |
| System.out.print("l"); |
| System.out.print("d"); |
| System.out.println("!"); |
| } |
| |
| @NeverSingleCallerInline |
| static void simpleIfNotNullTest(Object o) { |
| if (o != null) { |
| return; |
| } |
| System.out.print("H"); |
| System.out.print("e"); |
| System.out.print("l"); |
| System.out.print("l"); |
| System.out.print("o"); |
| System.out.print(" "); |
| System.out.print("w"); |
| System.out.print("o"); |
| System.out.print("r"); |
| System.out.print("l"); |
| System.out.print("d"); |
| System.out.println("!"); |
| } |
| |
| @NeverSingleCallerInline |
| static void simpleIfBothNotNullTest(Object o1, Object o2) { |
| if (o1 != null && o2 != null) { |
| return; |
| } |
| System.out.print("H"); |
| System.out.print("e"); |
| System.out.print("l"); |
| System.out.print("l"); |
| System.out.print("o"); |
| System.out.print(" "); |
| System.out.print("w"); |
| System.out.print("o"); |
| System.out.print("r"); |
| System.out.print("l"); |
| System.out.print("d"); |
| System.out.println("!"); |
| } |
| } |
| } |