[ApiModel] Amend the synthetic marker annotation with api-level
Fixes: b/268596049
Change-Id: Id6e5a12ca1888745741ff399f0c62f2f9e769b19
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index aff4bff..e24a22c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
+import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
@@ -15,6 +17,7 @@
import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -56,6 +59,9 @@
public final int visibility;
public final DexEncodedAnnotation annotation;
+ private static final int UNKNOWN_API_LEVEL = -1;
+ private static final int NOT_SET_API_LEVEL = -2;
+
private static void specify(StructuralSpecification<DexAnnotation, ?> spec) {
spec.withItem(a -> a.annotation).withInt(a -> a.visibility);
}
@@ -469,26 +475,37 @@
}
public static DexAnnotation createAnnotationSynthesizedClass(
- SyntheticKind kind, DexItemFactory dexItemFactory) {
+ SyntheticKind kind, DexItemFactory dexItemFactory, ComputedApiLevel computedApiLevel) {
DexString versionHash =
dexItemFactory.createString(dexItemFactory.getSyntheticNaming().getVersionHash());
DexAnnotationElement kindElement =
new DexAnnotationElement(dexItemFactory.kindString, DexValueInt.create(kind.getId()));
DexAnnotationElement versionHashElement =
new DexAnnotationElement(dexItemFactory.versionHashString, new DexValueString(versionHash));
- DexAnnotationElement[] elements = new DexAnnotationElement[] {kindElement, versionHashElement};
+ int apiLevel = getApiLevelForSerialization(computedApiLevel);
+ DexAnnotationElement apiLevelElement =
+ new DexAnnotationElement(dexItemFactory.apiLevelString, DexValueInt.create(apiLevel));
+ DexAnnotationElement[] elements =
+ new DexAnnotationElement[] {apiLevelElement, kindElement, versionHashElement};
return new DexAnnotation(
VISIBILITY_BUILD,
new DexEncodedAnnotation(dexItemFactory.annotationSynthesizedClass, elements));
}
public static boolean hasSynthesizedClassAnnotation(
- DexAnnotationSet annotations, DexItemFactory factory, SyntheticItems synthetics) {
- return getSynthesizedClassAnnotationInfo(annotations, factory, synthetics) != null;
+ DexAnnotationSet annotations,
+ DexItemFactory factory,
+ SyntheticItems synthetics,
+ AndroidApiLevelCompute apiLevelCompute) {
+ return getSynthesizedClassAnnotationInfo(annotations, factory, synthetics, apiLevelCompute)
+ != null;
}
- public static SyntheticKind getSynthesizedClassAnnotationInfo(
- DexAnnotationSet annotations, DexItemFactory factory, SyntheticItems synthetics) {
+ public static SynthesizedAnnotationClassInfo getSynthesizedClassAnnotationInfo(
+ DexAnnotationSet annotations,
+ DexItemFactory factory,
+ SyntheticItems synthetics,
+ AndroidApiLevelCompute apiLevelCompute) {
if (annotations.size() != 1) {
return null;
}
@@ -497,12 +514,13 @@
return null;
}
int length = annotation.annotation.elements.length;
- if (length != 2) {
+ if (length != 3) {
return null;
}
assert factory.kindString.isLessThan(factory.versionHashString);
- DexAnnotationElement kindElement = annotation.annotation.elements[0];
- DexAnnotationElement versionHashElement = annotation.annotation.elements[1];
+ DexAnnotationElement apiLevelElement = annotation.annotation.elements[0];
+ DexAnnotationElement kindElement = annotation.annotation.elements[1];
+ DexAnnotationElement versionHashElement = annotation.annotation.elements[2];
if (kindElement.name != factory.kindString) {
return null;
}
@@ -515,14 +533,43 @@
if (!versionHashElement.value.isDexValueString()) {
return null;
}
+ if (apiLevelElement.name != factory.apiLevelString || !apiLevelElement.value.isDexValueInt()) {
+ return null;
+ }
String currentVersionHash = synthetics.getNaming().getVersionHash();
String syntheticVersionHash = versionHashElement.value.asDexValueString().getValue().toString();
if (!currentVersionHash.equals(syntheticVersionHash)) {
return null;
}
- SyntheticKind kind =
+ int apiLevelValue = apiLevelElement.value.asDexValueInt().getValue();
+ ComputedApiLevel computedApiLevel = getSerializedApiLevel(apiLevelCompute, apiLevelValue);
+ SyntheticKind syntheticKind =
synthetics.getNaming().fromId(kindElement.value.asDexValueInt().getValue());
- return kind;
+ assert syntheticKind != synthetics.getNaming().API_MODEL_OUTLINE
+ || computedApiLevel.isKnownApiLevel();
+ return SynthesizedAnnotationClassInfo.create(syntheticKind, computedApiLevel);
+ }
+
+ private static int getApiLevelForSerialization(ComputedApiLevel computedApiLevel) {
+ if (computedApiLevel.isNotSetApiLevel()) {
+ return NOT_SET_API_LEVEL;
+ } else if (computedApiLevel.isUnknownApiLevel()) {
+ return UNKNOWN_API_LEVEL;
+ } else {
+ assert computedApiLevel.isKnownApiLevel();
+ return computedApiLevel.asKnownApiLevel().getApiLevel().getLevel();
+ }
+ }
+
+ private static ComputedApiLevel getSerializedApiLevel(
+ AndroidApiLevelCompute apiLevelCompute, int apiLevelValue) {
+ if (apiLevelValue == NOT_SET_API_LEVEL) {
+ return ComputedApiLevel.notSet();
+ } else if (apiLevelValue == UNKNOWN_API_LEVEL) {
+ return ComputedApiLevel.unknown();
+ } else {
+ return apiLevelCompute.of(AndroidApiLevel.getAndroidApiLevel(apiLevelValue));
+ }
}
public DexAnnotation rewrite(Function<DexEncodedAnnotation, DexEncodedAnnotation> rewriter) {
@@ -535,4 +582,29 @@
}
return new DexAnnotation(visibility, rewritten);
}
+
+ public static class SynthesizedAnnotationClassInfo {
+
+ private final SyntheticKind syntheticKind;
+ private final ComputedApiLevel computedApiLevel;
+
+ private SynthesizedAnnotationClassInfo(
+ SyntheticKind syntheticKind, ComputedApiLevel computedApiLevel) {
+ this.syntheticKind = syntheticKind;
+ this.computedApiLevel = computedApiLevel;
+ }
+
+ private static SynthesizedAnnotationClassInfo create(
+ SyntheticKind syntheticKind, ComputedApiLevel computedApiLevel) {
+ return new SynthesizedAnnotationClassInfo(syntheticKind, computedApiLevel);
+ }
+
+ public SyntheticKind getSyntheticKind() {
+ return syntheticKind;
+ }
+
+ public ComputedApiLevel getComputedApiLevel() {
+ return computedApiLevel;
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 4ffba91..df3709f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -356,6 +356,7 @@
public final DexString valueString = createString("value");
public final DexString kindString = createString("kind");
public final DexString versionHashString = createString("versionHash");
+ public final DexString apiLevelString = createString("apiLevel");
// Prefix for runtime affecting yet potential class-retained annotations.
public final DexString dalvikAnnotationOptimizationPrefix =
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index be7bf1c..2d11359 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.horizontalclassmerging.policies.AllInstantiatedOrUninstantiated;
import com.android.tools.r8.horizontalclassmerging.policies.CheckAbstractClasses;
import com.android.tools.r8.horizontalclassmerging.policies.CheckSyntheticClasses;
-import com.android.tools.r8.horizontalclassmerging.policies.ComputeApiLevelOfSyntheticClass;
import com.android.tools.r8.horizontalclassmerging.policies.FinalizeMergeGroup;
import com.android.tools.r8.horizontalclassmerging.policies.LimitClassGroups;
import com.android.tools.r8.horizontalclassmerging.policies.LimitInterfaceGroups;
@@ -143,8 +142,7 @@
ImmutableList.Builder<SingleClassPolicy> builder =
ImmutableList.<SingleClassPolicy>builder()
.add(new CheckSyntheticClasses(appView))
- .add(new OnlyClassesWithStaticDefinitionsAndNoClassInitializer())
- .add(new ComputeApiLevelOfSyntheticClass(appView));
+ .add(new OnlyClassesWithStaticDefinitionsAndNoClassInitializer());
assert verifySingleClassPoliciesIrrelevantForMergingSyntheticsInD8(appView, mode, builder);
return builder.build();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/ComputeApiLevelOfSyntheticClass.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/ComputeApiLevelOfSyntheticClass.java
deleted file mode 100644
index 9038a57..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/ComputeApiLevelOfSyntheticClass.java
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright (c) 2022, 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.horizontalclassmerging.policies;
-
-import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
-import com.android.tools.r8.androidapi.ComputedApiLevel;
-import com.android.tools.r8.dex.code.CfOrDexInstruction;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexMethodHandle;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
-import com.android.tools.r8.synthesis.SyntheticItems;
-import java.util.ListIterator;
-
-public class ComputeApiLevelOfSyntheticClass extends SingleClassPolicy {
-
- private final AppView<?> appView;
- private final SyntheticItems syntheticItems;
-
- public ComputeApiLevelOfSyntheticClass(AppView<?> appView) {
- this.appView = appView;
- this.syntheticItems = appView.getSyntheticItems();
- }
-
- @Override
- public boolean canMerge(DexProgramClass clazz) {
- assert syntheticItems.isSyntheticClass(clazz);
- clazz.forEachProgramMethod(
- programMethod -> {
- DexEncodedMethod definition = programMethod.getDefinition();
- if (definition.getApiLevelForCode().isNotSetApiLevel()) {
- ComputeApiLevelUseRegistry computeApiLevel =
- new ComputeApiLevelUseRegistry(appView, programMethod, appView.apiLevelCompute());
- computeApiLevel.accept(programMethod);
- ComputedApiLevel maxApiReferenceLevel = computeApiLevel.getMaxApiReferenceLevel();
- assert !maxApiReferenceLevel.isNotSetApiLevel();
- definition.setApiLevelForCode(maxApiReferenceLevel);
- definition.setApiLevelForDefinition(computeApiLevel.getMaxApiReferenceLevel());
- }
- });
- return true;
- }
-
- @Override
- public String getName() {
- return "ComputeApiLevelOfSyntheticClass";
- }
-
- private static class ComputeApiLevelUseRegistry extends UseRegistry<ProgramMethod> {
-
- private final AppView<?> appView;
- private final AndroidApiLevelCompute apiLevelCompute;
- private ComputedApiLevel maxApiReferenceLevel;
-
- public ComputeApiLevelUseRegistry(
- AppView<?> appView, ProgramMethod context, AndroidApiLevelCompute apiLevelCompute) {
- super(appView, context);
- this.appView = appView;
- this.apiLevelCompute = apiLevelCompute;
- maxApiReferenceLevel = appView.computedMinApiLevel();
- }
-
- @Override
- public void registerInitClass(DexType clazz) {
- assert false : "Unexpected call to an instruction that should not exist on DEX";
- }
-
- @Override
- public void registerRecordFieldValues(DexField[] fields) {
- assert false : "Unexpected call to an instruction that should not exist on DEX";
- }
-
- @Override
- public void registerInvokeVirtual(DexMethod invokedMethod) {
- setMaxApiReferenceLevel(invokedMethod);
- }
-
- @Override
- public void registerInvokeDirect(DexMethod invokedMethod) {
- setMaxApiReferenceLevel(invokedMethod);
- }
-
- @Override
- public void registerInvokeStatic(DexMethod invokedMethod) {
- setMaxApiReferenceLevel(invokedMethod);
- }
-
- @Override
- public void registerInvokeInterface(DexMethod invokedMethod) {
- setMaxApiReferenceLevel(invokedMethod);
- }
-
- @Override
- public void registerInvokeSuper(DexMethod invokedMethod) {
- setMaxApiReferenceLevel(invokedMethod);
- }
-
- @Override
- public void registerInstanceFieldRead(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerInstanceFieldReadFromMethodHandle(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerInstanceFieldWrite(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerInstanceFieldWriteFromMethodHandle(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerNewInstance(DexType type) {
- setMaxApiReferenceLevel(type);
- }
-
- @Override
- public void registerStaticFieldRead(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerStaticFieldReadFromMethodHandle(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerStaticFieldWrite(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerStaticFieldWriteFromMethodHandle(DexField field) {
- setMaxApiReferenceLevel(field);
- }
-
- @Override
- public void registerConstClass(
- DexType type,
- ListIterator<? extends CfOrDexInstruction> iterator,
- boolean ignoreCompatRules) {
- // Intentionally empty.
- }
-
- @Override
- public void registerCheckCast(DexType type, boolean ignoreCompatRules) {
- // Intentionally empty.
- }
-
- @Override
- public void registerSafeCheckCast(DexType type) {
- // Intentionally empty.
- }
-
- @Override
- public void registerTypeReference(DexType type) {
- // Intentionally empty.
- }
-
- @Override
- public void registerInstanceOf(DexType type) {
- // Intentionally empty.
- }
-
- @Override
- public void registerExceptionGuard(DexType guard) {
- setMaxApiReferenceLevel(guard);
- }
-
- @Override
- public void registerMethodHandle(DexMethodHandle methodHandle, MethodHandleUse use) {
- assert false : "Unexpected call to an instruction that should not exist on DEX";
- }
-
- @Override
- public void registerCallSite(DexCallSite callSite) {
- assert false : "Unexpected call to an instruction that should not exist on DEX";
- }
-
- private void setMaxApiReferenceLevel(DexReference reference) {
- maxApiReferenceLevel =
- maxApiReferenceLevel.max(apiLevelCompute.computeApiLevelForLibraryReference(reference));
- }
-
- public ComputedApiLevel getMaxApiReferenceLevel() {
- return maxApiReferenceLevel;
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
index 0024b64..0e899f7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.horizontalclassmerging.policies;
import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiReferenceLevelForMerging;
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.getMembersApiReferenceLevelForMerging;
import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
import com.android.tools.r8.androidapi.ComputedApiLevel;
@@ -15,14 +16,16 @@
public class NoDifferentApiReferenceLevel extends MultiClassSameReferencePolicy<ComputedApiLevel> {
private final AndroidApiLevelCompute apiLevelCompute;
- private final AppView<?> appView;
private final boolean enableApiCallerIdentification;
+ private final boolean enableWholeProgramOptimization;
+ private final ComputedApiLevel minApiLevel;
public NoDifferentApiReferenceLevel(AppView<?> appView) {
- this.appView = appView;
apiLevelCompute = appView.apiLevelCompute();
enableApiCallerIdentification =
appView.options().apiModelingOptions().isApiCallerIdentificationEnabled();
+ enableWholeProgramOptimization = appView.enableWholeProgramOptimizations();
+ minApiLevel = appView.computedMinApiLevel();
}
@Override
@@ -39,7 +42,9 @@
public ComputedApiLevel getMergeKey(DexProgramClass clazz) {
assert enableApiCallerIdentification;
ComputedApiLevel apiReferenceLevelForMerging =
- getApiReferenceLevelForMerging(appView, apiLevelCompute, clazz);
+ enableWholeProgramOptimization
+ ? getApiReferenceLevelForMerging(apiLevelCompute, clazz)
+ : getMembersApiReferenceLevelForMerging(clazz, minApiLevel);
if (apiReferenceLevelForMerging.isUnknownApiLevel()) {
return ineligibleForClassMerging();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
index 4cc4154..8baf037 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
@@ -14,6 +15,7 @@
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
@@ -22,6 +24,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.Box;
import java.util.Set;
import java.util.function.Consumer;
@@ -41,6 +44,9 @@
}
public void run(Set<DexType> roots) {
+ SyntheticItems syntheticItems = appView.getSyntheticItems();
+ DexItemFactory factory = appView.dexItemFactory();
+ AndroidApiLevelCompute apiLevelCompute = appView.apiLevelCompute();
for (DexType type : roots) {
DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
// Should only happen for library classes, which are filtered out.
@@ -48,7 +54,7 @@
consumer.accept(type);
// Super and interfaces are live, no need to add them.
if (!DexAnnotation.hasSynthesizedClassAnnotation(
- clazz.annotations(), appView.dexItemFactory(), appView.getSyntheticItems())) {
+ clazz.annotations(), factory, syntheticItems, apiLevelCompute)) {
traceAnnotationsDirectDependencies(clazz.annotations());
}
clazz.forEachField(field -> consumer.accept(field.getReference().type));
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index da2b320..dc4c7ea 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -537,9 +537,9 @@
// somewhat expensive.
if (appView.options().apiModelingOptions().isApiCallerIdentificationEnabled()) {
ComputedApiLevel sourceApiLevel =
- getApiReferenceLevelForMerging(appView, apiLevelCompute, sourceClass);
+ getApiReferenceLevelForMerging(apiLevelCompute, sourceClass);
ComputedApiLevel targetApiLevel =
- getApiReferenceLevelForMerging(appView, apiLevelCompute, targetClass);
+ getApiReferenceLevelForMerging(apiLevelCompute, targetClass);
if (!sourceApiLevel.equals(targetApiLevel)) {
if (Log.ENABLED) {
AbortReason.API_REFERENCE_LEVEL.printLogMessageForClass(sourceClass);
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index ebb3ba0..8214303 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -572,7 +572,7 @@
DexProgramClass externalSyntheticClass,
AppView<?> appView) {
if (shouldAnnotateSynthetics(appView.options())) {
- SyntheticMarker.addMarkerToClass(externalSyntheticClass, kind, appView.options());
+ SyntheticMarker.addMarkerToClass(externalSyntheticClass, kind, appView);
}
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
index 67dbe6a..aebc9ae 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
@@ -6,14 +6,15 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotation.SynthesizedAnnotationClassInfo;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.AndroidApiLevelUtils;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.InternalOptions;
import java.nio.charset.StandardCharsets;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ByteVector;
@@ -108,14 +109,18 @@
}
public static void addMarkerToClass(
- DexProgramClass clazz, SyntheticKind kind, InternalOptions options) {
+ DexProgramClass clazz, SyntheticKind kind, AppView<?> appView) {
// TODO(b/158159959): Consider moving this to the dex writer similar to the CF case.
- assert !options.isGeneratingClassFiles();
+ assert !appView.options().isGeneratingClassFiles();
clazz.setAnnotations(
clazz
.annotations()
.getWithAddedOrReplaced(
- DexAnnotation.createAnnotationSynthesizedClass(kind, options.itemFactory)));
+ DexAnnotation.createAnnotationSynthesizedClass(
+ kind,
+ appView.options().itemFactory,
+ AndroidApiLevelUtils.getApiReferenceLevelForMerging(
+ appView.apiLevelCompute(), clazz))));
}
public static SyntheticMarker stripMarkerFromClass(DexProgramClass clazz, AppView<?> appView) {
@@ -134,7 +139,10 @@
SyntheticMarker marker = internalStripMarkerFromClass(clazz, appView);
assert marker != NO_MARKER
|| !DexAnnotation.hasSynthesizedClassAnnotation(
- clazz.annotations(), appView.dexItemFactory(), appView.getSyntheticItems());
+ clazz.annotations(),
+ appView.dexItemFactory(),
+ appView.getSyntheticItems(),
+ appView.apiLevelCompute());
return marker;
}
@@ -146,13 +154,17 @@
if (isDefinitelyNotSyntheticProgramClass(clazz)) {
return NO_MARKER;
}
- SyntheticKind kind =
+ SynthesizedAnnotationClassInfo synthesizedInfo =
DexAnnotation.getSynthesizedClassAnnotationInfo(
- clazz.annotations(), appView.dexItemFactory(), appView.getSyntheticItems());
- if (kind == null) {
+ clazz.annotations(),
+ appView.dexItemFactory(),
+ appView.getSyntheticItems(),
+ appView.apiLevelCompute());
+ if (synthesizedInfo == null) {
return NO_MARKER;
}
assert clazz.annotations().size() == 1;
+ SyntheticKind kind = synthesizedInfo.getSyntheticKind();
if (kind.isSingleSyntheticMethod()) {
if (!clazz.interfaces.isEmpty()) {
return NO_MARKER;
@@ -164,6 +176,7 @@
}
}
clazz.setAnnotations(DexAnnotationSet.empty());
+ clazz.forEachMethod(method -> method.setApiLevelForCode(synthesizedInfo.getComputedApiLevel()));
DexType context = getSyntheticContextType(clazz.type, kind, appView.dexItemFactory());
return new SyntheticMarker(
kind, SynthesizingContext.fromSyntheticInputClass(clazz, context, appView));
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 841bf9a..3067de7 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -65,20 +65,24 @@
}
public static ComputedApiLevel getApiReferenceLevelForMerging(
- AppView<?> appView, AndroidApiLevelCompute apiLevelCompute, DexProgramClass clazz) {
+ AndroidApiLevelCompute apiLevelCompute, DexProgramClass clazz) {
// The api level of a class is the max level of it's members, super class and interfaces.
return getMembersApiReferenceLevelForMerging(
clazz, apiLevelCompute.computeApiLevelForDefinition(clazz.allImmediateSupertypes()));
}
- private static ComputedApiLevel getMembersApiReferenceLevelForMerging(
+ public static ComputedApiLevel getMembersApiReferenceLevelForMerging(
DexProgramClass clazz, ComputedApiLevel memberLevel) {
// Based on b/138781768#comment57 there is almost no penalty for having an unknown reference
// as long as we are not invoking or accessing a field on it. Therefore we can disregard static
// types of fields and only consider method code api levels.
for (DexEncodedMethod method : clazz.methods()) {
if (method.hasCode()) {
- memberLevel = memberLevel.max(method.getApiLevelForCode());
+ ComputedApiLevel apiLevelForCode = method.getApiLevelForCode();
+ if (apiLevelForCode.isNotSetApiLevel()) {
+ return ComputedApiLevel.notSet();
+ }
+ memberLevel = memberLevel.max(apiLevelForCode);
}
if (memberLevel.isUnknownApiLevel()) {
return memberLevel;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 7480fc8..19177be 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1909,18 +1909,6 @@
public void disableStubbingOfClasses() {
enableStubbingOfClasses = false;
}
-
- private boolean isThrowable(AppView<?> appView, DexLibraryClass libraryClass) {
- DexClass current = libraryClass;
- while (current.getSuperType() != null) {
- DexType superType = current.getSuperType();
- if (superType == appView.dexItemFactory().throwableType) {
- return true;
- }
- current = appView.definitionFor(current.getSuperType());
- }
- return false;
- }
}
public static class ProtoShrinkingOptions {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
index 6560933..f0b5d28 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
@@ -7,17 +7,13 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.SingleTestRunResult;
@@ -127,22 +123,13 @@
}
@Test
- public void testD8ReleaseForApiLevelWithOutlining() {
+ public void testD8ReleaseForApiLevelWithOutlining() throws Exception {
assumeTrue(parameters.isDexRuntime());
assumeTrue(willHorizontallyMergeOutlines());
- // TODO(b/268596049): Ensure that we can obtain the api level for outlines.
- CompilationFailedException compilationFailedException =
- assertThrows(
- CompilationFailedException.class,
- () ->
- testD8(
- CompilationMode.RELEASE,
- this::inspectNumberOfClassesFromOutput,
- // We can pass any inspector since horizontal merging fails.
- classesInspector -> {}));
- Throwable cause = compilationFailedException.getCause();
- assertNotNull(cause);
- assertThat(cause.getMessage(), containsString("Verification of single class policies failed"));
+ testD8(
+ CompilationMode.RELEASE,
+ this::inspectNumberOfClassesFromOutput,
+ HorizontallyMergedClassesInspector::assertNoClassesMerged);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerDexTest.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerDexTest.java
index 5b00775..fd37907 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerDexTest.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerDexTest.java
@@ -68,7 +68,7 @@
DexAnnotation[] annotations = clazz.getDexProgramClass().annotations().annotations;
assertEquals(1, annotations.length);
DexEncodedAnnotation annotation = annotations[0].annotation;
- assertEquals(2, annotation.elements.length);
+ assertEquals(3, annotation.elements.length);
assertEquals(
"com.android.tools.r8.annotations.SynthesizedClassV2",
annotation.type.toSourceString());