[ApiModel] Assign api-level to all library definitions
This CL also adds computation for api level for forwarding bridges added during memberrebinding.
Bug: b/235184674
Change-Id: I8060650b66e56d1324027ae260853c71083ca59a
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 4196ca2..53ba483 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1102,8 +1102,14 @@
.build());
}
+ public DexEncodedMethod toForwardingMethod(DexClass newHolder, AppView<?> definitions) {
+ return toForwardingMethod(newHolder, definitions, ConsumerUtils.emptyConsumer());
+ }
+
public DexEncodedMethod toForwardingMethod(
- DexClass newHolder, DexDefinitionSupplier definitions) {
+ DexClass newHolder,
+ AppView<?> definitions,
+ Consumer<DexEncodedMethod.Builder> builderConsumer) {
DexMethod newMethod = getReference().withHolder(newHolder, definitions.dexItemFactory());
checkIfObsolete();
@@ -1149,6 +1155,7 @@
.modifyAccessFlags(MethodAccessFlags::setBridge))
.setIsLibraryMethodOverrideIf(
!isStatic() && !isLibraryMethodOverride().isUnknown(), isLibraryMethodOverride())
+ .apply(builderConsumer)
.build();
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index aebbc12..30a6dfa 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.LookupTarget;
@@ -70,6 +71,11 @@
}
@Override
+ public void processNewLiveNonProgramType(ClasspathOrLibraryClass clazz) {
+ clazz.forEachClassMethod(this::computeAndSetApiLevelForDefinition);
+ }
+
+ @Override
public void notifyMarkVirtualDispatchTargetAsLive(
LookupTarget target, EnqueuerWorklist worklist) {
target.accept(
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index 8dc26d6..d587b61 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph.analysis;
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.LookupTarget;
@@ -35,6 +36,9 @@
Enqueuer enqueuer,
EnqueuerWorklist worklist) {}
+ /** Called when a non program class is visited and marked live */
+ public void processNewLiveNonProgramType(ClasspathOrLibraryClass clazz) {}
+
/** Called when a method's code has been processed by the registry. */
public void processTracedCode(
ProgramMethod method, DefaultEnqueuerUseRegistry registry, EnqueuerWorklist worklist) {}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index c7395e9..483fdb4 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -35,6 +35,7 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -354,15 +355,30 @@
(bridgeHolder, targets) -> {
// Sorting the list of bridges within a class maintains a deterministic order of entries
// in the method collection.
- targets.sort((p1, p2) -> p1.getFirst().compareTo(p2.getFirst()));
+ targets.sort(Comparator.comparing(Pair::getFirst));
for (Pair<DexMethod, DexClassAndMethod> pair : targets) {
DexMethod method = pair.getFirst();
DexClassAndMethod target = pair.getSecond();
DexMethod bridgeMethod =
method.withHolder(bridgeHolder.getType(), appView.dexItemFactory());
if (bridgeHolder.getMethodCollection().getMethod(bridgeMethod) == null) {
+ DexEncodedMethod targetDefinition = target.getDefinition();
DexEncodedMethod bridgeMethodDefinition =
- target.getDefinition().toForwardingMethod(bridgeHolder, appView);
+ targetDefinition.toForwardingMethod(
+ bridgeHolder,
+ appView,
+ builder -> {
+ if (!targetDefinition.isAbstract()
+ && targetDefinition.getApiLevelForCode().isNotSetApiLevel()) {
+ assert target.isLibraryMethod();
+ builder.setApiLevelForCode(
+ appView
+ .apiLevelCompute()
+ .computeApiLevelForLibraryReference(
+ targetDefinition.getReference(),
+ appView.computedMinApiLevel()));
+ }
+ });
bridgeHolder.addMethod(bridgeMethodDefinition);
}
assert resolver.apply(method).getResolvedMethod().getReference() == bridgeMethod;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index c1f0b40..4907c2f 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -745,6 +745,7 @@
// rules.
handleLibraryTypeInheritingFromProgramType(clazz.asLibraryClass());
}
+ analyses.forEach(analysis -> analysis.processNewLiveNonProgramType(clazz));
clazz.forEachClassField(
field ->
addNonProgramClassToWorklist(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java
index 023a738..b90b066 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java
@@ -48,7 +48,9 @@
diagnostics -> {
// TODO(b/235184674): Should not throw with an error.
diagnostics.assertErrorMessageThatMatches(
- containsString("Cannot compute relationship for not set"));
+ containsString(
+ "Unexpected virtual method without library method override"
+ + " information"));
}));
}