Check for safe api inlining in ClassInliner
Bug: 138781768
Bug: 188388130
Change-Id: I1a9d417c0a6bedc7c3026aa16733d44b4cb14d49
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index e653838..4e18dcd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo.isApiSafeForInlining;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unreachable;
@@ -879,7 +880,12 @@
if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) {
return null;
}
-
+ // Check the api level is allowed to be inlined.
+ if (isApiSafeForInlining(
+ method.getOptimizationInfo(), singleTarget.getOptimizationInfo(), appView.options())
+ .isPossiblyFalse()) {
+ return null;
+ }
// Check that the entire constructor chain can be inlined into the current context.
DexMethod parent = instanceInitializerInfo.getParent();
while (parent != dexItemFactory.objectMembers.constructor) {
@@ -906,6 +912,14 @@
NopWhyAreYouNotInliningReporter.getInstance())) {
return null;
}
+ // Check the api level is allowed to be inlined.
+ if (isApiSafeForInlining(
+ method.getOptimizationInfo(),
+ encodedParentMethod.getOptimizationInfo(),
+ appView.options())
+ .isPossiblyFalse()) {
+ return null;
+ }
parent =
encodedParentMethod
.getOptimizationInfo()
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
index e482f59..f4609d4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
@@ -53,8 +53,12 @@
.compile()
.inspect(
inspector -> {
- // TODO(b/138781768): Should not be class inlined.
- assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+ if (parameters.isDexRuntime()
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+ assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+ } else {
+ assertThat(inspector.clazz(ApiCaller.class), isPresent());
+ }
})
.addRunClasspathClasses(Api.class)
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
index ac42465..22ecf86 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
@@ -5,13 +5,15 @@
package com.android.tools.r8.apimodel;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
-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.TestParametersCollection;
+import com.android.tools.r8.apimodel.ApiModelNoClassInliningFieldTest.ApiCallerCaller;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.lang.reflect.Method;
import org.junit.Test;
@@ -36,8 +38,6 @@
@Test
public void testR8() throws Exception {
Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
- Method apiCaller = ApiCaller.class.getDeclaredMethod("callApi");
- Method apiCallerCaller = ApiCallerCaller.class.getDeclaredMethod("callCallApi");
testForR8(parameters.getBackend())
.addProgramClasses(ApiCaller.class, ApiCallerCaller.class, Main.class)
.addLibraryClasses(Api.class)
@@ -50,8 +50,14 @@
.apply(ApiModelingTestHelper::enableApiCallerIdentification)
.compile()
.inspect(
- verifyThat(parameters, apiCaller)
- .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
+ inspector -> {
+ if (parameters.isDexRuntime()
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+ assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+ } else {
+ assertThat(inspector.clazz(ApiCaller.class), isPresent());
+ }
+ })
.addRunClasspathClasses(Api.class)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("Api::apiLevel22");
@@ -72,19 +78,10 @@
}
}
- @NoHorizontalClassMerging
- public static class ApiCallerCaller {
-
- @NeverInline
- public static void callCallApi() {
- new ApiCaller().callApi();
- }
- }
-
public static class Main {
public static void main(String[] args) {
- ApiCallerCaller.callCallApi();
+ new ApiCaller().callApi();
}
}
}