Account for native calls in clinit cycle analysis
Bug: b/341537881
Change-Id: Ia25b58bac14cfd7dd09d2a5ef1cdd3ec7b3fefa9
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
index ec45f9d..7dd373a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
@@ -333,6 +332,8 @@
}
boolean enqueueMethod(ProgramMethod method) {
+ assert !method.getAccessFlags().isAbstract();
+ assert !method.getAccessFlags().isNative();
if (seenMethods.add(method)) {
worklist.addLast(method);
return true;
@@ -341,6 +342,9 @@
}
void enqueueTracingRoot(ProgramMethod tracingRoot) {
+ assert tracingRoot.getDefinition().isClassInitializer();
+ assert !tracingRoot.getAccessFlags().isAbstract();
+ assert !tracingRoot.getAccessFlags().isNative();
boolean added = seenMethods.add(tracingRoot);
assert added;
worklist.add(tracingRoot);
@@ -490,12 +494,19 @@
public void registerInvokeDirect(DexMethod method) {
DexMethod rewrittenMethod =
appView.graphLens().lookupInvokeDirect(method, getContext(), codeLens).getReference();
- MethodResolutionResult resolutionResult =
- appView().appInfo().resolveMethodOnClassHolderLegacy(rewrittenMethod);
- if (resolutionResult.isSingleResolution()
- && resolutionResult.getResolvedHolder().isProgramClass()) {
- enqueueMethod(resolutionResult.getResolvedProgramMethod());
+ ProgramMethod resolvedMethod =
+ appView()
+ .appInfo()
+ .resolveMethodOnClassHolderLegacy(rewrittenMethod)
+ .getResolvedProgramMethod();
+ if (resolvedMethod == null) {
+ return;
}
+ if (resolvedMethod.getAccessFlags().isNative()) {
+ fail();
+ return;
+ }
+ enqueueMethod(resolvedMethod);
}
@Override
@@ -524,10 +535,15 @@
.appInfo()
.unsafeResolveMethodDueToDexFormatLegacy(rewrittenMethod)
.getResolvedProgramMethod();
- if (resolvedMethod != null) {
- triggerClassInitializerIfNotAlreadyTriggeredInContext(resolvedMethod.getHolder());
- enqueueMethod(resolvedMethod);
+ if (resolvedMethod == null) {
+ return;
}
+ if (resolvedMethod.getAccessFlags().isNative()) {
+ fail();
+ return;
+ }
+ triggerClassInitializerIfNotAlreadyTriggeredInContext(resolvedMethod.getHolder());
+ enqueueMethod(resolvedMethod);
}
@Override
@@ -537,9 +553,14 @@
ProgramMethod superTarget =
asProgramMethodOrNull(
appView().appInfo().lookupSuperTarget(rewrittenMethod, getContext(), appView()));
- if (superTarget != null) {
- enqueueMethod(superTarget);
+ if (superTarget == null) {
+ return;
}
+ if (superTarget.getAccessFlags().isNative()) {
+ fail();
+ return;
+ }
+ enqueueMethod(superTarget);
}
@Override
@@ -554,7 +575,8 @@
if (resolvedMethod == null) {
return;
}
- if (!resolvedMethod.getHolder().isEffectivelyFinal(appView)) {
+ if (!resolvedMethod.getHolder().isEffectivelyFinal(appView)
+ || resolvedMethod.getAccessFlags().isNative()) {
fail();
return;
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitCycleAnalysisWithNativeCallTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitCycleAnalysisWithNativeCallTest.java
index 0bc0925..d6ab35d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitCycleAnalysisWithNativeCallTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitCycleAnalysisWithNativeCallTest.java
@@ -3,11 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.classmerging.horizontal;
-import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilation;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -27,14 +27,15 @@
@Test
public void test() throws Exception {
- // TODO(b/341537881): Account for the native call.
- assertFailsCompilation(
- () ->
- testForR8(parameters.getBackend())
- .addInnerClasses(getClass())
- .addKeepMainRule(Main.class)
- .setMinApi(parameters)
- .compile());
+ // Checks that compilation succeeds (as opposed to dereferencing the code object of a native
+ // method, as in b/341537881).
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addHorizontallyMergedClassesInspector(
+ HorizontallyMergedClassesInspector::assertNoClassesMerged)
+ .setMinApi(parameters)
+ .compile();
}
static class Main {