Reland "[ApiModel] Use ComputedApiLevel instead of AndroidApiLevel" This reverts commit ab84d34a0141d2cb892ab78d98c27d2450512a5a. Bug: 207452750 Change-Id: I67dc36d1983bad82df910366b4ecf2d69f39c8b8
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index 72c0cbb..722ae3e 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -104,7 +104,6 @@ import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer; import com.android.tools.r8.synthesis.SyntheticFinalization; import com.android.tools.r8.synthesis.SyntheticItems; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AndroidApp; import com.android.tools.r8.utils.CfgPrinter; import com.android.tools.r8.utils.CollectionUtils; @@ -880,10 +879,10 @@ for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) { clazz.forEachProgramMember( member -> { - assert member.getDefinition().getApiLevel() != AndroidApiLevel.NOT_SET + assert !member.getDefinition().getApiLevel().isNotSetApiLevel() : "Every member should have been analyzed"; assert appView.options().apiModelingOptions().enableApiCallerIdentification - || member.getDefinition().getApiLevel() == AndroidApiLevel.UNKNOWN + || member.getDefinition().getApiLevel().isUnknownApiLevel() : "Every member should have level UNKNOWN"; }); }
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java index 34a2d65..48d4d4f 100644 --- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java +++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
@@ -4,67 +4,108 @@ package com.android.tools.r8.androidapi; -import static com.android.tools.r8.utils.AndroidApiLevel.UNKNOWN; - +import com.android.tools.r8.androidapi.ComputedApiLevel.KnownApiLevel; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMember; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.InternalOptions; -public interface AndroidApiLevelCompute { +public abstract class AndroidApiLevelCompute { - AndroidApiLevel computeApiLevelForLibraryReference(DexReference reference); + private final KnownApiLevel[] knownApiLevelCache; - AndroidApiLevel computeApiLevelForDefinition(Iterable<DexType> types); - - default AndroidApiLevel computeApiLevelForDefinition( - DexMember<?, ?> reference, DexItemFactory factory) { - return computeApiLevelForDefinition(reference.getReferencedBaseTypes(factory)); + public AndroidApiLevelCompute() { + knownApiLevelCache = new KnownApiLevel[AndroidApiLevel.LATEST.getLevel() + 1]; + for (AndroidApiLevel value : AndroidApiLevel.values()) { + if (value != AndroidApiLevel.ANDROID_PLATFORM) { + knownApiLevelCache[value.getLevel()] = new KnownApiLevel(value); + } + } } - static AndroidApiLevelCompute create(AppView<?> appView) { + public KnownApiLevel of(AndroidApiLevel apiLevel) { + if (apiLevel == AndroidApiLevel.ANDROID_PLATFORM) { + return ComputedApiLevel.platform(); + } + return knownApiLevelCache[apiLevel.getLevel()]; + } + + public abstract ComputedApiLevel computeApiLevelForLibraryReference( + DexReference reference, ComputedApiLevel unknownValue); + + public abstract ComputedApiLevel computeApiLevelForDefinition( + Iterable<DexType> types, ComputedApiLevel unknownValue); + + public ComputedApiLevel computeApiLevelForDefinition( + DexMember<?, ?> reference, DexItemFactory factory, ComputedApiLevel unknownValue) { + return computeApiLevelForDefinition(reference.getReferencedBaseTypes(factory), unknownValue); + } + + public static AndroidApiLevelCompute create(AppView<?> appView) { return appView.options().apiModelingOptions().enableApiCallerIdentification ? new DefaultAndroidApiLevelCompute(appView) : new NoAndroidApiLevelCompute(); } - class NoAndroidApiLevelCompute implements AndroidApiLevelCompute { - - @Override - public AndroidApiLevel computeApiLevelForDefinition(Iterable<DexType> types) { - return UNKNOWN; - } - - @Override - public AndroidApiLevel computeApiLevelForLibraryReference(DexReference reference) { - return UNKNOWN; + public static ComputedApiLevel computeInitialMinApiLevel(InternalOptions options) { + if (options.apiModelingOptions().enableApiCallerIdentification) { + return options.getMinApiLevel() == AndroidApiLevel.ANDROID_PLATFORM + ? ComputedApiLevel.platform() + : new KnownApiLevel(options.getMinApiLevel()); + } else { + return ComputedApiLevel.unknown(); } } - class DefaultAndroidApiLevelCompute implements AndroidApiLevelCompute { + public ComputedApiLevel getPlatformApiLevelOrUnknown(AppView<?> appView) { + if (appView.options().getMinApiLevel() == AndroidApiLevel.ANDROID_PLATFORM) { + return ComputedApiLevel.platform(); + } + return ComputedApiLevel.unknown(); + } - private final AndroidApiReferenceLevelCache cache; - private final AndroidApiLevel minApiLevel; + public static class NoAndroidApiLevelCompute extends AndroidApiLevelCompute { - public DefaultAndroidApiLevelCompute(AppView<?> appView) { - this.cache = AndroidApiReferenceLevelCache.create(appView); - this.minApiLevel = appView.options().getMinApiLevel(); + @Override + public ComputedApiLevel computeApiLevelForDefinition( + Iterable<DexType> types, ComputedApiLevel unknownValue) { + return unknownValue; } @Override - public AndroidApiLevel computeApiLevelForDefinition(Iterable<DexType> types) { - AndroidApiLevel computedLevel = minApiLevel; + public ComputedApiLevel computeApiLevelForLibraryReference( + DexReference reference, ComputedApiLevel unknownValue) { + return unknownValue; + } + } + + public static class DefaultAndroidApiLevelCompute extends AndroidApiLevelCompute { + + private final AndroidApiReferenceLevelCache cache; + private final ComputedApiLevel minApiLevel; + + public DefaultAndroidApiLevelCompute(AppView<?> appView) { + this.cache = AndroidApiReferenceLevelCache.create(appView, this); + this.minApiLevel = of(appView.options().getMinApiLevel()); + } + + @Override + public ComputedApiLevel computeApiLevelForDefinition( + Iterable<DexType> types, ComputedApiLevel unknownValue) { + ComputedApiLevel computedLevel = minApiLevel; for (DexType type : types) { - computedLevel = cache.lookupMax(type, computedLevel); + computedLevel = cache.lookupMax(type, computedLevel, unknownValue); } return computedLevel; } @Override - public AndroidApiLevel computeApiLevelForLibraryReference(DexReference reference) { - return cache.lookup(reference); + public ComputedApiLevel computeApiLevelForLibraryReference( + DexReference reference, ComputedApiLevel unknownValue) { + return cache.lookup(reference, unknownValue); } } }
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java index 551085a..bedc254 100644 --- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java +++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java
@@ -4,12 +4,10 @@ package com.android.tools.r8.androidapi; -import static com.android.tools.r8.utils.AndroidApiLevel.NOT_SET; -import static com.android.tools.r8.utils.AndroidApiLevel.UNKNOWN; +import static com.android.tools.r8.utils.AndroidApiLevel.ANDROID_PLATFORM; import com.android.tools.r8.errors.CompilationError; 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.DexReference; import com.android.tools.r8.graph.DexType; @@ -41,25 +39,23 @@ new Int2ReferenceOpenHashMap<AndroidApiLevel>(); private final Map<String, AndroidApiLevel> ambiguousHashesWithApiLevel = new HashMap<>(); private final Map<DexReference, AndroidApiLevel> ambiguousCache = new IdentityHashMap<>(); - private final DexItemFactory factory; public AndroidApiLevelHashingDatabaseImpl( - DexItemFactory factory, List<AndroidApiForHashingClass> predefinedApiTypeLookup) { - this.factory = factory; + List<AndroidApiForHashingClass> predefinedApiTypeLookup) { loadData(); predefinedApiTypeLookup.forEach( apiClass -> { DexType type = apiClass.getType(); - lookupNonAmbiguousCache.put(type.hashCode(), NOT_SET); + lookupNonAmbiguousCache.put(type.hashCode(), null); ambiguousCache.put(type, apiClass.getApiLevel()); apiClass.visitMethodsWithApiLevels( (method, apiLevel) -> { - lookupNonAmbiguousCache.put(method.hashCode(), NOT_SET); + lookupNonAmbiguousCache.put(method.hashCode(), null); ambiguousCache.put(method, apiLevel); }); apiClass.visitFieldsWithApiLevels( (field, apiLevel) -> { - lookupNonAmbiguousCache.put(field.hashCode(), NOT_SET); + lookupNonAmbiguousCache.put(field.hashCode(), null); ambiguousCache.put(field, apiLevel); }); }); @@ -96,7 +92,7 @@ for (int i = 0; i < hashIndices.length; i++) { byte apiLevel = apiLevels[i]; lookupNonAmbiguousCache.put( - hashIndices[i], apiLevel == -1 ? NOT_SET : AndroidApiLevel.getAndroidApiLevel(apiLevel)); + hashIndices[i], apiLevel == -1 ? null : AndroidApiLevel.getAndroidApiLevel(apiLevel)); } ambiguous.forEach(this::parseAmbiguous); } @@ -130,9 +126,12 @@ } private AndroidApiLevel lookupApiLevel(DexReference reference) { - AndroidApiLevel result = lookupNonAmbiguousCache.getOrDefault(reference.hashCode(), UNKNOWN); - if (result != NOT_SET) { - return result; + // We use Android platform to track if an element is unknown since no occurrences of that api + // level exists in the database. + AndroidApiLevel result = + lookupNonAmbiguousCache.getOrDefault(reference.hashCode(), ANDROID_PLATFORM); + if (result != null) { + return result == ANDROID_PLATFORM ? null : result; } return ambiguousCache.computeIfAbsent( reference,
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java index 3cb2b7d..4e17f60 100644 --- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java +++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -17,87 +17,89 @@ public class AndroidApiReferenceLevelCache { private final DesugaredLibraryConfiguration desugaredLibraryConfiguration; + private final AndroidApiLevelCompute apiLevelCompute; private final AndroidApiLevelDatabase androidApiLevelDatabase; private final AppView<?> appView; private final DexItemFactory factory; - private AndroidApiReferenceLevelCache(AppView<?> appView) { - this(appView, ImmutableList.of()); - } - private AndroidApiReferenceLevelCache( - AppView<?> appView, List<AndroidApiForHashingClass> predefinedApiTypeLookupForHashing) { + AppView<?> appView, + AndroidApiLevelCompute apiLevelCompute, + List<AndroidApiForHashingClass> predefinedApiTypeLookupForHashing) { this.appView = appView; + this.apiLevelCompute = apiLevelCompute; factory = appView.dexItemFactory(); androidApiLevelDatabase = - new AndroidApiLevelHashingDatabaseImpl(factory, predefinedApiTypeLookupForHashing); + new AndroidApiLevelHashingDatabaseImpl(predefinedApiTypeLookupForHashing); desugaredLibraryConfiguration = appView.options().desugaredLibraryConfiguration; } - public static AndroidApiReferenceLevelCache create(AppView<?> appView) { - if (!appView.options().apiModelingOptions().enableApiCallerIdentification) { - // If enableApiCallerIdentification is not enabled then override lookup to always return - // AndroidApiLevel.B. - return new AndroidApiReferenceLevelCache(appView) { - @Override - public AndroidApiLevel lookup(DexReference reference) { - return AndroidApiLevel.B; - } - }; - } + public static AndroidApiReferenceLevelCache create( + AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) { + assert appView.options().apiModelingOptions().enableApiCallerIdentification; ImmutableList.Builder<AndroidApiForHashingClass> builder = ImmutableList.builder(); appView .options() .apiModelingOptions() .visitMockedApiLevelsForReferences(appView.dexItemFactory(), builder::add); - return new AndroidApiReferenceLevelCache(appView, builder.build()); + return new AndroidApiReferenceLevelCache(appView, apiLevelCompute, builder.build()); } - public AndroidApiLevel lookupMax(DexReference reference, AndroidApiLevel minApiLevel) { - return lookup(reference).max(minApiLevel); + public ComputedApiLevel lookupMax( + DexReference reference, ComputedApiLevel minApiLevel, ComputedApiLevel unknownValue) { + assert !minApiLevel.isNotSetApiLevel(); + return lookup(reference, unknownValue).max(minApiLevel); } - public AndroidApiLevel lookup(DexReference reference) { + public ComputedApiLevel lookup(DexReference reference, ComputedApiLevel unknownValue) { DexType contextType = reference.getContextType(); if (contextType.isArrayType()) { if (reference.isDexMethod() && reference.asDexMethod().match(factory.objectMembers.clone)) { - return appView.options().getMinApiLevel(); + return appView.computedMinApiLevel(); } - return lookup(contextType.toBaseType(factory)); + return lookup(contextType.toBaseType(factory), unknownValue); } if (contextType.isPrimitiveType() || contextType.isVoidType()) { - return appView.options().getMinApiLevel(); + return appView.computedMinApiLevel(); } DexClass clazz = appView.definitionFor(contextType); if (clazz == null) { - return AndroidApiLevel.UNKNOWN; + return unknownValue; } if (!clazz.isLibraryClass()) { - return appView.options().getMinApiLevel(); + return appView.computedMinApiLevel(); } if (reference.getContextType() == factory.objectType) { - return appView.options().getMinApiLevel(); + return appView.computedMinApiLevel(); } if (desugaredLibraryConfiguration.isSupported(reference, appView)) { // If we end up desugaring the reference, the library classes is bridged by j$ which is part // of the program. - return appView.options().getMinApiLevel(); + return appView.computedMinApiLevel(); } - if (reference.isDexMethod() && factory.objectMembers.isObjectMember(reference.asDexMethod())) { + if (reference.isDexMethod() + && !reference.asDexMethod().isInstanceInitializer(factory) + && factory.objectMembers.isObjectMember(reference.asDexMethod())) { // If we can lookup the method it was introduced/overwritten later. Take for example - // a default constructor that was not available before som api level. If unknown we default + // a default toString that was not available before some api level. If unknown we default // back to the static holder. AndroidApiLevel methodApiLevel = androidApiLevelDatabase.getMethodApiLevel(reference.asDexMethod()); - return methodApiLevel == AndroidApiLevel.UNKNOWN - ? androidApiLevelDatabase.getTypeApiLevel(reference.getContextType()) - : methodApiLevel; + if (methodApiLevel != null) { + return apiLevelCompute.of(methodApiLevel); + } + AndroidApiLevel typeApiLevel = + androidApiLevelDatabase.getTypeApiLevel(reference.getContextType()); + // TODO(b/207452750): Investigate if we can return minApi here. + return typeApiLevel == null ? ComputedApiLevel.unknown() : apiLevelCompute.of(typeApiLevel); } - return reference - .apply( + AndroidApiLevel foundApiLevel = + reference.apply( androidApiLevelDatabase::getTypeApiLevel, androidApiLevelDatabase::getFieldApiLevel, - androidApiLevelDatabase::getMethodApiLevel) - .max(appView.options().getMinApiLevel()); + androidApiLevelDatabase::getMethodApiLevel); + return (foundApiLevel == null) + ? unknownValue + : apiLevelCompute.of(foundApiLevel.max(appView.options().getMinApiLevel())); } }
diff --git a/src/main/java/com/android/tools/r8/androidapi/ComputedApiLevel.java b/src/main/java/com/android/tools/r8/androidapi/ComputedApiLevel.java new file mode 100644 index 0000000..2f5ab5e --- /dev/null +++ b/src/main/java/com/android/tools/r8/androidapi/ComputedApiLevel.java
@@ -0,0 +1,165 @@ +// Copyright (c) 2021, 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.androidapi; + +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.structural.Equatable; +import java.util.Objects; + +/** + * The ComputedApiLevel encodes a lattice over AndroidApiLevel with a bottom (NotSet) and a top + * (Unknown). + */ +public interface ComputedApiLevel extends Equatable<ComputedApiLevel> { + + static NotSetApiLevel notSet() { + return NotSetApiLevel.INSTANCE; + } + + static UnknownApiLevel unknown() { + return UnknownApiLevel.INSTANCE; + } + + static KnownApiLevel platform() { + return KnownApiLevel.PLATFORM_INSTANCE; + } + + default boolean isNotSetApiLevel() { + return false; + } + + default boolean isUnknownApiLevel() { + return false; + } + + default ComputedApiLevel max(ComputedApiLevel other) { + return isGreaterThanOrEqualTo(other) ? this : other; + } + + default boolean isGreaterThanOrEqualTo(ComputedApiLevel other) { + assert !isNotSetApiLevel() && !other.isNotSetApiLevel() + : "Cannot compute relationship for not set"; + if (isUnknownApiLevel()) { + return true; + } + if (other.isUnknownApiLevel()) { + return false; + } + assert isKnownApiLevel() && other.isKnownApiLevel(); + return asKnownApiLevel() + .getApiLevel() + .isGreaterThanOrEqualTo(other.asKnownApiLevel().getApiLevel()); + } + + default boolean isKnownApiLevel() { + return false; + } + + default KnownApiLevel asKnownApiLevel() { + return null; + } + + @Override + default boolean isEqualTo(ComputedApiLevel other) { + return this.equals(other); + } + + class NotSetApiLevel implements ComputedApiLevel { + + private static final NotSetApiLevel INSTANCE = new NotSetApiLevel(); + + private NotSetApiLevel() {} + + @Override + public boolean isNotSetApiLevel() { + return true; + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + } + + class UnknownApiLevel implements ComputedApiLevel { + + private static final UnknownApiLevel INSTANCE = new UnknownApiLevel(); + + private UnknownApiLevel() {} + + @Override + public boolean isUnknownApiLevel() { + return true; + } + + @Override + public String toString() { + return "UNKNOWN"; + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + } + + class KnownApiLevel implements ComputedApiLevel { + + private static final KnownApiLevel PLATFORM_INSTANCE = + new KnownApiLevel(AndroidApiLevel.ANDROID_PLATFORM); + + private final AndroidApiLevel apiLevel; + + KnownApiLevel(AndroidApiLevel apiLevel) { + this.apiLevel = apiLevel; + } + + public AndroidApiLevel getApiLevel() { + return apiLevel; + } + + @Override + public boolean isKnownApiLevel() { + return true; + } + + @Override + public KnownApiLevel asKnownApiLevel() { + return this; + } + + @Override + public String toString() { + return apiLevel.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof KnownApiLevel)) { + return false; + } + KnownApiLevel that = (KnownApiLevel) o; + return apiLevel == that.apiLevel; + } + + @Override + public int hashCode() { + return Objects.hash(apiLevel); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java index 32e1f64..e21fbf4 100644 --- a/src/main/java/com/android/tools/r8/graph/AppView.java +++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -4,6 +4,8 @@ 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.contexts.CompilationContext; import com.android.tools.r8.contexts.CompilationContext.ProcessorContext; import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration; @@ -116,6 +118,8 @@ private final Thread mainThread = Thread.currentThread(); + private final ComputedApiLevel computedMinApiLevel; + private AppView( T appInfo, WholeProgramOptimizations wholeProgramOptimizations, @@ -137,6 +141,8 @@ this.libraryMethodSideEffectModelCollection = new LibraryMethodSideEffectModelCollection(this); this.libraryMemberOptimizer = new LibraryMemberOptimizer(this); this.protoShrinker = ProtoShrinker.create(withLiveness()); + + this.computedMinApiLevel = AndroidApiLevelCompute.computeInitialMinApiLevel(appInfo.options()); } public boolean verifyMainThread() { @@ -827,4 +833,8 @@ public boolean checkForTesting(Supplier<Boolean> test) { return testing().enableTestAssertions ? test.get() : true; } + + public ComputedApiLevel computedMinApiLevel() { + return computedMinApiLevel; + } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java index 56a302d..44a5132 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -7,6 +7,7 @@ import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature; import com.android.tools.r8.ir.analysis.type.TypeElement; @@ -21,7 +22,6 @@ import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; import com.android.tools.r8.kotlin.KotlinFieldLevelInfo; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.ConsumerUtils; import com.android.tools.r8.utils.structural.StructuralItem; import com.android.tools.r8.utils.structural.StructuralMapping; @@ -59,7 +59,7 @@ FieldTypeSignature genericSignature, DexAnnotationSet annotations, DexValue staticValue, - AndroidApiLevel apiLevel, + ComputedApiLevel apiLevel, boolean deprecated, boolean d8R8Synthesized) { super(field, annotations, d8R8Synthesized, apiLevel); @@ -103,7 +103,7 @@ } @Override - public AndroidApiLevel getApiLevel() { + public ComputedApiLevel getApiLevel() { return getApiLevelForDefinition(); } @@ -365,7 +365,7 @@ private FieldAccessFlags accessFlags; private FieldTypeSignature genericSignature = FieldTypeSignature.noSignature(); private DexValue staticValue = null; - private AndroidApiLevel apiLevel = AndroidApiLevel.NOT_SET; + private ComputedApiLevel apiLevel = ComputedApiLevel.notSet(); private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance(); private boolean deprecated; private final boolean d8R8Synthesized; @@ -438,7 +438,7 @@ return this; } - public Builder setApiLevel(AndroidApiLevel apiLevel) { + public Builder setApiLevel(ComputedApiLevel apiLevel) { this.apiLevel = apiLevel; return this; } @@ -474,7 +474,7 @@ assert accessFlags != null; assert genericSignature != null; assert annotations != null; - assert !checkAndroidApiLevel || apiLevel != AndroidApiLevel.NOT_SET; + assert !checkAndroidApiLevel || !apiLevel.isNotSetApiLevel(); DexEncodedField dexEncodedField = new DexEncodedField( field,
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java index a5ea49e..7f42e49 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -3,11 +3,9 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.graph; -import static com.android.tools.r8.utils.AndroidApiLevel.NOT_SET; - +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo; import com.android.tools.r8.kotlin.KotlinMemberLevelInfo; -import com.android.tools.r8.utils.AndroidApiLevel; import java.util.function.Consumer; import java.util.function.Function; @@ -23,7 +21,7 @@ private final boolean d8R8Synthesized; /** apiLevelForDefinition describes the api level needed for knowing all types */ - private AndroidApiLevel apiLevelForDefinition; + private ComputedApiLevel apiLevelForDefinition; private final R reference; @@ -31,7 +29,7 @@ R reference, DexAnnotationSet annotations, boolean d8R8Synthesized, - AndroidApiLevel apiLevelForDefinition) { + ComputedApiLevel apiLevelForDefinition) { super(annotations); this.reference = reference; this.d8R8Synthesized = d8R8Synthesized; @@ -95,18 +93,18 @@ public abstract MemberOptimizationInfo<?> getOptimizationInfo(); - public abstract AndroidApiLevel getApiLevel(); + public abstract ComputedApiLevel getApiLevel(); - public AndroidApiLevel getApiLevelForDefinition() { + public ComputedApiLevel getApiLevelForDefinition() { return apiLevelForDefinition; } - public void setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) { + public void setApiLevelForDefinition(ComputedApiLevel apiLevelForDefinition) { this.apiLevelForDefinition = apiLevelForDefinition; } public boolean hasComputedApiReferenceLevel() { - return getApiLevel() != NOT_SET; + return !getApiLevel().isNotSetApiLevel(); } @Override
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 ccf7d83..a8709ec 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -11,10 +11,10 @@ import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE; import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo; -import static com.android.tools.r8.utils.AndroidApiLevel.NOT_SET; import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer; import static java.util.Objects.requireNonNull; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.cf.code.CfConstNumber; import com.android.tools.r8.cf.code.CfConstString; @@ -71,7 +71,6 @@ import com.android.tools.r8.naming.NamingLens; import com.android.tools.r8.position.MethodPosition; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.ConsumerUtils; import com.android.tools.r8.utils.InternalOptions; @@ -148,8 +147,8 @@ ParameterAnnotationsList.empty(), null, false, - NOT_SET, - NOT_SET, + ComputedApiLevel.notSet(), + ComputedApiLevel.notSet(), null, CallSiteOptimizationInfo.top(), DefaultMethodOptimizationInfo.getInstance(), @@ -168,7 +167,7 @@ private CallSiteOptimizationInfo callSiteOptimizationInfo; private CfVersion classFileVersion; /** The apiLevelForCode describes the api level needed for knowing all references in the code */ - private AndroidApiLevel apiLevelForCode; + private ComputedApiLevel apiLevelForCode; private KotlinMethodLevelInfo kotlinMemberInfo = getNoKotlinInfo(); /** Generic signature information if the attribute is present in the input */ @@ -242,8 +241,8 @@ ParameterAnnotationsList parameterAnnotationsList, Code code, boolean d8R8Synthesized, - AndroidApiLevel apiLevelForDefinition, - AndroidApiLevel apiLevelForCode, + ComputedApiLevel apiLevelForDefinition, + ComputedApiLevel apiLevelForCode, CfVersion classFileVersion, CallSiteOptimizationInfo callSiteOptimizationInfo, MethodOptimizationInfo optimizationInfo, @@ -1232,7 +1231,7 @@ .fixupOptimizationInfo(appView, prototypeChanges.createMethodOptimizationInfoFixer()) .setGenericSignature(MethodTypeSignature.noSignature()); DexEncodedMethod method = builder.build(); - method.copyMetadata(this); + method.copyMetadata(appView, this); setObsolete(); return method; } @@ -1268,23 +1267,23 @@ return optimizationInfo; } - public AndroidApiLevel getApiLevelForCode() { + public ComputedApiLevel getApiLevelForCode() { return apiLevelForCode; } - public void clearApiLevelForCode(AppView<?> appView) { - this.apiLevelForCode = AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView); + public void clearApiLevelForCode() { + this.apiLevelForCode = ComputedApiLevel.notSet(); } - public void setApiLevelForCode(AndroidApiLevel apiLevel) { + public void setApiLevelForCode(ComputedApiLevel apiLevel) { assert apiLevel != null; this.apiLevelForCode = apiLevel; } @Override - public AndroidApiLevel getApiLevel() { - return (shouldNotHaveCode() ? AndroidApiLevel.B : getApiLevelForCode()) - .max(getApiLevelForDefinition()); + public ComputedApiLevel getApiLevel() { + ComputedApiLevel apiLevelForDefinition = getApiLevelForDefinition(); + return shouldNotHaveCode() ? apiLevelForDefinition : apiLevelForDefinition.max(apiLevelForCode); } public synchronized MutableMethodOptimizationInfo getMutableOptimizationInfo() { @@ -1320,12 +1319,14 @@ this.callSiteOptimizationInfo = callSiteOptimizationInfo; } - public void copyMetadata(DexEncodedMethod from) { + public void copyMetadata(AppView<?> appView, DexEncodedMethod from) { checkIfObsolete(); if (from.hasClassFileVersion()) { upgradeClassFileVersion(from.getClassFileVersion()); } - apiLevelForCode = getApiLevelForCode().max(from.getApiLevelForCode()); + if (appView.options().apiModelingOptions().enableApiCallerIdentification) { + apiLevelForCode = getApiLevelForCode().max(from.getApiLevelForCode()); + } } public MethodTypeSignature getGenericSignature() { @@ -1374,8 +1375,8 @@ private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance(); private KotlinMethodLevelInfo kotlinInfo = getNoKotlinInfo(); private CfVersion classFileVersion = null; - private AndroidApiLevel apiLevelForDefinition = NOT_SET; - private AndroidApiLevel apiLevelForCode = NOT_SET; + private ComputedApiLevel apiLevelForDefinition = ComputedApiLevel.notSet(); + private ComputedApiLevel apiLevelForCode = ComputedApiLevel.notSet(); private final boolean d8R8Synthesized; private boolean deprecated = false; @@ -1611,12 +1612,12 @@ return this; } - public Builder setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) { + public Builder setApiLevelForDefinition(ComputedApiLevel apiLevelForDefinition) { this.apiLevelForDefinition = apiLevelForDefinition; return this; } - public Builder setApiLevelForCode(AndroidApiLevel apiLevelForCode) { + public Builder setApiLevelForCode(ComputedApiLevel apiLevelForCode) { this.apiLevelForCode = apiLevelForCode; return this; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java index e297bd4..900e79c 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -4,11 +4,12 @@ package com.android.tools.r8.graph; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static com.google.common.base.Predicates.alwaysTrue; import com.android.tools.r8.ProgramResource; import com.android.tools.r8.ProgramResource.Kind; +import com.android.tools.r8.androidapi.AndroidApiLevelCompute; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; @@ -21,7 +22,6 @@ import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.AppInfoWithLiveness; import com.android.tools.r8.synthesis.SyntheticMarker; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.TraversalContinuation; import com.android.tools.r8.utils.structural.Ordered; import com.android.tools.r8.utils.structural.StructuralItem; @@ -34,7 +34,6 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -823,26 +822,19 @@ return checksumSupplier; } - public AndroidApiLevel getApiReferenceLevel( - AppView<?> appView, - BiFunction<DexReference, AndroidApiLevel, AndroidApiLevel> apiLevelLookup) { + public ComputedApiLevel getApiReferenceLevel( + AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) { // The api level of a class is the max level of it's members, super class and interfaces. - AndroidApiLevel computedApiLevel = minApiLevelIfEnabledOrUnknown(appView); - for (DexType superType : allImmediateSupertypes()) { - computedApiLevel = apiLevelLookup.apply(superType, computedApiLevel); - if (computedApiLevel == AndroidApiLevel.UNKNOWN) { - return AndroidApiLevel.UNKNOWN; - } - } - return computedApiLevel.max(getMembersApiReferenceLevel(appView)); + return getMembersApiReferenceLevel( + apiLevelCompute.computeApiLevelForDefinition( + allImmediateSupertypes(), apiLevelCompute.getPlatformApiLevelOrUnknown(appView))); } - public AndroidApiLevel getMembersApiReferenceLevel(AppView<?> appView) { - AndroidApiLevel memberLevel = minApiLevelIfEnabledOrUnknown(appView); + public ComputedApiLevel getMembersApiReferenceLevel(ComputedApiLevel memberLevel) { for (DexEncodedMember<?, ?> member : members()) { memberLevel = memberLevel.max(member.getApiLevel()); - if (memberLevel == AndroidApiLevel.UNKNOWN) { - return AndroidApiLevel.UNKNOWN; + if (memberLevel.isUnknownApiLevel()) { + return memberLevel; } } return memberLevel;
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java index 844b45e..cf866d4 100644 --- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java +++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -17,7 +17,6 @@ import com.android.tools.r8.origin.Origin; import com.android.tools.r8.position.MethodPosition; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.AndroidApiLevel; /** Type representing a method definition in the programs compilation unit and its holder. */ public final class ProgramMethod extends DexClassAndMethod @@ -95,7 +94,7 @@ accessFlags.demoteFromStrict(); accessFlags.demoteFromSynchronized(); accessFlags.promoteToAbstract(); - getDefinition().clearApiLevelForCode(appView); + getDefinition().clearApiLevelForCode(); getDefinition().unsetCode(); getSimpleFeedback().unsetOptimizationInfoForAbstractMethod(this); } @@ -105,7 +104,7 @@ public void convertToThrowNullMethod(AppView<?> appView) { MethodAccessFlags accessFlags = getAccessFlags(); accessFlags.demoteFromAbstract(); - getDefinition().setApiLevelForCode(AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView)); + getDefinition().setApiLevelForCode(appView.computedMinApiLevel()); getDefinition().setCode(ThrowNullCode.get(), appView); getSimpleFeedback().markProcessed(getDefinition(), ConstraintWithTarget.ALWAYS); getSimpleFeedback().unsetOptimizationInfoForThrowNullMethod(this);
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 7f4b9f9..45e2065 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
@@ -5,6 +5,7 @@ package com.android.tools.r8.graph.analysis; 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.DexClassAndMember; import com.android.tools.r8.graph.DexEncodedMethod; @@ -13,18 +14,17 @@ import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry; -import com.android.tools.r8.utils.AndroidApiLevel; public class ApiModelAnalysis extends EnqueuerAnalysis { private final AppView<?> appView; - private final AndroidApiLevel minApiLevel; private final AndroidApiLevelCompute apiCompute; + private final ComputedApiLevel minApiLevel; public ApiModelAnalysis(AppView<?> appView, AndroidApiLevelCompute apiCompute) { this.appView = appView; - this.minApiLevel = appView.options().getMinApiLevel(); this.apiCompute = apiCompute; + this.minApiLevel = appView.computedMinApiLevel(); } @Override @@ -73,7 +73,7 @@ @Override public void notifyFailedMethodResolutionTarget(DexEncodedMethod method) { // We may not trace into failed resolution targets. - method.setApiLevelForCode(AndroidApiLevel.UNKNOWN); + method.setApiLevelForCode(ComputedApiLevel.unknown()); } private void computeAndSetApiLevelForDefinition(DexClassAndMember<?, ?> member) { @@ -81,6 +81,8 @@ .getDefinition() .setApiLevelForDefinition( apiCompute.computeApiLevelForDefinition( - member.getReference(), appView.dexItemFactory())); + member.getReference(), + appView.dexItemFactory(), + apiCompute.getPlatformApiLevelOrUnknown(appView))); } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java index b1055ef..c76f43f 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -4,9 +4,9 @@ package com.android.tools.r8.horizontalclassmerging; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static com.google.common.base.Predicates.not; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; @@ -29,7 +29,6 @@ import com.android.tools.r8.ir.analysis.value.NumberFromIntervalValue; import com.android.tools.r8.ir.optimize.info.OptimizationFeedback; import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.SetUtils; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; @@ -125,7 +124,7 @@ newMethodReference.withName("$r8$clinit$synthetic", dexItemFactory); lensBuilder.recordNewMethodSignature(syntheticMethodReference, newMethodReference, true); - AndroidApiLevel apiReferenceLevel = classInitializerMerger.getApiReferenceLevel(appView); + ComputedApiLevel apiReferenceLevel = classInitializerMerger.getApiReferenceLevel(appView); DexEncodedMethod definition = DexEncodedMethod.syntheticBuilder() .setMethod(newMethodReference) @@ -215,7 +214,7 @@ DexEncodedField.syntheticBuilder() .setField(group.getClassIdField()) .setAccessFlags(FieldAccessFlags.createPublicFinalSynthetic()) - .setApiLevel(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevel(appView.computedMinApiLevel()) .build(); // For the $r8$classId synthesized fields, we try to over-approximate the set of values it may
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java index 085276f..b1219c4 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -4,9 +4,9 @@ package com.android.tools.r8.horizontalclassmerging.code; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static java.lang.Integer.max; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.cf.code.CfGoto; import com.android.tools.r8.cf.code.CfInstruction; @@ -36,7 +36,6 @@ import com.android.tools.r8.ir.code.Return; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.origin.Origin; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.CfVersionUtils; import com.android.tools.r8.utils.IterableUtils; import com.android.tools.r8.utils.ListUtils; @@ -101,11 +100,11 @@ return null; } - public AndroidApiLevel getApiReferenceLevel(AppView<?> appView) { + public ComputedApiLevel getApiReferenceLevel(AppView<?> appView) { assert !classInitializers.isEmpty(); return ListUtils.fold( classInitializers, - minApiLevelIfEnabledOrUnknown(appView), + appView.computedMinApiLevel(), (accApiLevel, method) -> accApiLevel.max(method.getDefinition().getApiLevel())); }
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 3b7e1e0..1f953f4 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
@@ -4,21 +4,21 @@ package com.android.tools.r8.horizontalclassmerging.policies; -import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache; +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.DexProgramClass; import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy; -import com.android.tools.r8.utils.AndroidApiLevel; -public class NoDifferentApiReferenceLevel extends MultiClassSameReferencePolicy<AndroidApiLevel> { +public class NoDifferentApiReferenceLevel extends MultiClassSameReferencePolicy<ComputedApiLevel> { - private final AndroidApiReferenceLevelCache apiReferenceLevelCache; + private final AndroidApiLevelCompute apiLevelCompute; private final AppView<?> appView; // TODO(b/188388130): Remove when stabilized. private final boolean enableApiCallerIdentification; public NoDifferentApiReferenceLevel(AppView<?> appView) { - apiReferenceLevelCache = AndroidApiReferenceLevelCache.create(appView); + apiLevelCompute = AndroidApiLevelCompute.create(appView); this.appView = appView; enableApiCallerIdentification = appView.options().apiModelingOptions().enableApiCallerIdentification; @@ -35,8 +35,8 @@ } @Override - public AndroidApiLevel getMergeKey(DexProgramClass clazz) { + public ComputedApiLevel getMergeKey(DexProgramClass clazz) { assert enableApiCallerIdentification; - return clazz.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax); + return clazz.getApiReferenceLevel(appView, apiLevelCompute); } }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java index 2b72d1e..37ce381 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -205,7 +205,6 @@ .map(prefix -> "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix)) .map(options.itemFactory::createString) .collect(Collectors.toList()); - AndroidApiLevelCompute apiLevelCompute = AndroidApiLevelCompute.create(appView); if (options.isDesugaredLibraryCompilation()) { // Specific L8 Settings, performs all desugaring including L8 specific desugaring. // @@ -223,8 +222,7 @@ // - nest based access desugaring, // - invoke-special desugaring. assert options.desugarState.isOn(); - this.instructionDesugaring = - CfInstructionDesugaringCollection.create(appView, apiLevelCompute); + this.instructionDesugaring = CfInstructionDesugaringCollection.create(appView); this.covariantReturnTypeAnnotationTransformer = null; this.dynamicTypeOptimization = null; this.classInliner = null; @@ -249,7 +247,7 @@ this.instructionDesugaring = appView.enableWholeProgramOptimizations() ? CfInstructionDesugaringCollection.empty() - : CfInstructionDesugaringCollection.create(appView, apiLevelCompute); + : CfInstructionDesugaringCollection.create(appView); this.covariantReturnTypeAnnotationTransformer = options.processCovariantReturnTypeAnnotations ? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory()) @@ -288,7 +286,8 @@ this.typeChecker = new TypeChecker(appViewWithLiveness, VerifyTypesHelper.create(appView)); this.serviceLoaderRewriter = options.enableServiceLoaderRewriting - ? new ServiceLoaderRewriter(appViewWithLiveness, apiLevelCompute) + ? new ServiceLoaderRewriter( + appViewWithLiveness, AndroidApiLevelCompute.create(appView)) : null; this.enumValueOptimizer = options.enableEnumValueOptimization ? new EnumValueOptimizer(appViewWithLiveness) : null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java index c516da4..ed1260e 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.ir.desugar; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; - import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.cf.code.CfInvoke; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; @@ -1470,8 +1468,7 @@ appView, builder -> builder - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .disableAndroidApiLevelCheck() .setProto(getProto(appView.dexItemFactory())) .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setCode(methodSig -> generateTemplateMethod(appView.options(), methodSig)));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java index 8328e9b..b34a515 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
@@ -4,7 +4,6 @@ package com.android.tools.r8.ir.desugar; -import com.android.tools.r8.androidapi.AndroidApiLevelCompute; import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.graph.AppView; @@ -28,19 +27,16 @@ */ public abstract class CfInstructionDesugaringCollection { - public static CfInstructionDesugaringCollection create( - AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) { + public static CfInstructionDesugaringCollection create(AppView<?> appView) { if (appView.options().desugarState.isOn()) { - return new NonEmptyCfInstructionDesugaringCollection(appView, apiLevelCompute); + return new NonEmptyCfInstructionDesugaringCollection(appView); } // TODO(b/145775365): invoke-special desugaring is mandatory, since we currently can't map // invoke-special instructions that require desugaring into IR. if (appView.options().isGeneratingClassFiles()) { - return NonEmptyCfInstructionDesugaringCollection.createForCfToCfNonDesugar( - appView, apiLevelCompute); + return NonEmptyCfInstructionDesugaringCollection.createForCfToCfNonDesugar(appView); } - return NonEmptyCfInstructionDesugaringCollection.createForCfToDexNonDesugar( - appView, apiLevelCompute); + return NonEmptyCfInstructionDesugaringCollection.createForCfToDexNonDesugar(appView); } public static CfInstructionDesugaringCollection empty() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java index cd17565..a014283 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -645,7 +645,7 @@ .setApiLevelForDefinition(encodedMethod.getApiLevelForDefinition()) .setApiLevelForCode(encodedMethod.getApiLevelForCode()) .build(); - newMethod.copyMetadata(encodedMethod); + newMethod.copyMetadata(appView, encodedMethod); forcefullyMovedLambdaMethodConsumer.acceptForcefullyMovedLambdaMethod( encodedMethod.getReference(), callTarget); @@ -736,7 +736,7 @@ .setApiLevelForDefinition(encodedMethod.getApiLevelForDefinition()) .setApiLevelForCode(encodedMethod.getApiLevelForCode()) .build(); - newMethod.copyMetadata(encodedMethod); + newMethod.copyMetadata(appView, encodedMethod); forcefullyMovedLambdaMethodConsumer.acceptForcefullyMovedLambdaMethod( encodedMethod.getReference(), callTarget); return newMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java index 66d3a56..bc5c0fa 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -4,7 +4,6 @@ package com.android.tools.r8.ir.desugar; -import com.android.tools.r8.androidapi.AndroidApiLevelCompute; import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.errors.Unreachable; @@ -52,12 +51,9 @@ private final DesugaredLibraryRetargeter desugaredLibraryRetargeter; private final InterfaceMethodRewriter interfaceMethodRewriter; private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter; - private final AndroidApiLevelCompute apiLevelCompute; - NonEmptyCfInstructionDesugaringCollection( - AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) { + NonEmptyCfInstructionDesugaringCollection(AppView<?> appView) { this.appView = appView; - this.apiLevelCompute = apiLevelCompute; AlwaysThrowingInstructionDesugaring alwaysThrowingInstructionDesugaring = appView.enableWholeProgramOptimizations() ? new AlwaysThrowingInstructionDesugaring(appView.withClassHierarchy()) @@ -131,24 +127,22 @@ } } - static NonEmptyCfInstructionDesugaringCollection createForCfToCfNonDesugar( - AppView<?> appView, AndroidApiLevelCompute computeApiLevel) { + static NonEmptyCfInstructionDesugaringCollection createForCfToCfNonDesugar(AppView<?> appView) { assert appView.options().desugarState.isOff(); assert appView.options().isGeneratingClassFiles(); NonEmptyCfInstructionDesugaringCollection desugaringCollection = - new NonEmptyCfInstructionDesugaringCollection(appView, computeApiLevel); + new NonEmptyCfInstructionDesugaringCollection(appView); // TODO(b/145775365): special constructor for cf-to-cf compilations with desugaring disabled. // This should be removed once we can represent invoke-special instructions in the IR. desugaringCollection.desugarings.add(new InvokeSpecialToSelfDesugaring(appView)); return desugaringCollection; } - static NonEmptyCfInstructionDesugaringCollection createForCfToDexNonDesugar( - AppView<?> appView, AndroidApiLevelCompute computeApiLevel) { + static NonEmptyCfInstructionDesugaringCollection createForCfToDexNonDesugar(AppView<?> appView) { assert appView.options().desugarState.isOff(); assert appView.options().isGeneratingDex(); NonEmptyCfInstructionDesugaringCollection desugaringCollection = - new NonEmptyCfInstructionDesugaringCollection(appView, computeApiLevel); + new NonEmptyCfInstructionDesugaringCollection(appView); desugaringCollection.desugarings.add(new InvokeSpecialToSelfDesugaring(appView)); desugaringCollection.desugarings.add(new InvokeToPrivateRewriter()); return desugaringCollection;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java index 3f9e078..fb848df 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -6,7 +6,6 @@ import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.CACHE_CONSTANT; import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.THROW_ICCE; import static com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass.Behaviour.THROW_NSME; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import com.android.tools.r8.cf.code.CfCheckCast; @@ -56,7 +55,6 @@ import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.MethodSynthesizerConsumer; import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations; import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.collections.ImmutableDeque; import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap; import com.google.common.collect.ImmutableList; @@ -194,12 +192,12 @@ DexEncodedField.syntheticBuilder() .setField(this.initializedValueField) .setAccessFlags(FieldAccessFlags.createPrivateStaticSynthetic()) - .setApiLevel(minApiLevelIfEnabledOrUnknown(appView)) + .disableAndroidApiLevelCheck() .build(), DexEncodedField.syntheticBuilder() .setField(this.constantValueField) .setAccessFlags(FieldAccessFlags.createPrivateStaticSynthetic()) - .setApiLevel(minApiLevelIfEnabledOrUnknown(appView)) + .disableAndroidApiLevelCheck() .build())); } @@ -210,8 +208,7 @@ .setMethod(getConstMethod) .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setCode(generateGetterCode(builder)) - .setApiLevelForDefinition(AndroidApiLevel.S) - .setApiLevelForCode(AndroidApiLevel.S) + .disableAndroidApiLevelCheck() .build())); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java index 5d9e05e..14240a6 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
@@ -4,8 +4,7 @@ package com.android.tools.r8.ir.desugar.desugaredlibrary; -import static com.android.tools.r8.utils.AndroidApiLevel.NOT_SET; - +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.CfCode; @@ -595,7 +594,8 @@ .setAccessFlags(newFlags) .setCode(code) .setApiLevelForDefinition(template.getApiLevelForDefinition()) - .setApiLevelForCode(code == null ? NOT_SET : template.getApiLevelForCode()) + .setApiLevelForCode( + code == null ? ComputedApiLevel.notSet() : template.getApiLevelForCode()) .build(); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java index e1462ea..36519f8 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.ir.desugar.itf; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; - import com.android.tools.r8.cf.code.CfInvoke; import com.android.tools.r8.cf.code.CfNew; import com.android.tools.r8.cf.code.CfStackInstruction; @@ -802,8 +800,7 @@ .setAccessFlags(accessFlags) .setCode( createExceptionThrowingCfCode(newMethod, accessFlags, errorType, dexItemFactory)) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .disableAndroidApiLevelCheck() .build(); addSyntheticMethod(clazz.asProgramClass(), newEncodedMethod); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java index 674493f..510331b 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -1088,7 +1088,7 @@ context.getDefinition().accessFlags.demoteFromSynthetic(); } - context.getDefinition().copyMetadata(singleTargetMethod); + context.getDefinition().copyMetadata(appView, singleTargetMethod); if (inlineeMayHaveInvokeMethod && options.applyInliningToInlinee) { if (inlineeStack.size() + 1 > options.applyInliningToInlineeMaxDepth
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java index d73ac60..7ef7216 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
@@ -7,6 +7,7 @@ import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull; import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.contexts.CompilationContext.ProcessorContext; import com.android.tools.r8.dex.Constants; @@ -68,7 +69,6 @@ import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.AppInfoWithLiveness; 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.InternalOptions.OutlineOptions; import com.android.tools.r8.utils.ListUtils; @@ -1527,8 +1527,8 @@ .setProto(outline.buildProto()) // It is OK to set the api level to UNKNOWN since we are not interested in // inlining the outlines anyway. - .setApiLevelForDefinition(AndroidApiLevel.UNKNOWN) - .setApiLevelForCode(AndroidApiLevel.UNKNOWN) + .setApiLevelForDefinition(ComputedApiLevel.unknown()) + .setApiLevelForCode(ComputedApiLevel.unknown()) .setCode(m -> new OutlineCode(outline)); if (appView.options().isGeneratingClassFiles()) { builder.setClassFileVersion(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java index a735ad9..260a5a3 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.ir.optimize; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; - import com.android.tools.r8.androidapi.AndroidApiLevelCompute; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.graph.AppView; @@ -180,7 +178,8 @@ DexEncodedMethod addedMethod = createSynthesizedMethod(service, classes, methodProcessingContext); if (appView.options().isGeneratingClassFiles()) { - addedMethod.upgradeClassFileVersion(code.method().getClassFileVersion()); + addedMethod.upgradeClassFileVersion( + code.context().getDefinition().getClassFileVersion()); } return addedMethod; }); @@ -206,10 +205,11 @@ builder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setProto(proto) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) .setApiLevelForCode( apiLevelCompute.computeApiLevelForDefinition( - ListUtils.map(classes, clazz -> clazz.type))) + ListUtils.map(classes, clazz -> clazz.type), + apiLevelCompute.getPlatformApiLevelOrUnknown(appView))) .setCode( m -> ServiceLoaderSourceCode.generate( @@ -248,7 +248,7 @@ private final IRCode code; private final InvokeStatic serviceLoaderLoad; - private InstructionListIterator iterator; + private final InstructionListIterator iterator; Rewriter(IRCode code, InstructionListIterator iterator, InvokeStatic serviceLoaderLoad) { this.iterator = iterator;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java b/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java index aaeb960..5639925 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.ir.optimize; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; - import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.contexts.CompilationContext.UniqueContext; @@ -45,8 +43,8 @@ builder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setClassFileVersion(CfVersion.V1_8) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode(method -> getToStringIfNotNullCodeTemplate(method, options)) .setProto(proto)); return new UtilityMethodForCodeOptimizations(syntheticMethod); @@ -74,8 +72,8 @@ builder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setClassFileVersion(CfVersion.V1_8) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode( method -> getThrowClassCastExceptionIfNotNullCodeTemplate(method, options)) .setProto(proto)); @@ -104,8 +102,8 @@ builder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setClassFileVersion(CfVersion.V1_8) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode(method -> getThrowIllegalAccessErrorCodeTemplate(method, options)) .setProto(proto)); return new UtilityMethodForCodeOptimizations(syntheticMethod); @@ -132,8 +130,8 @@ builder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setClassFileVersion(CfVersion.V1_8) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode( method -> getThrowIncompatibleClassChangeErrorCodeTemplate(method, options)) .setProto(proto)); @@ -162,8 +160,8 @@ builder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setClassFileVersion(CfVersion.V1_8) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode(method -> getThrowNoSuchMethodErrorCodeTemplate(method, options)) .setProto(proto)); return new UtilityMethodForCodeOptimizations(syntheticMethod);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java index e392248..9997cc0 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.ir.optimize.enums; import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import com.android.tools.r8.contexts.CompilationContext.ProcessorContext; import com.android.tools.r8.graph.AppView; @@ -186,8 +185,8 @@ checkNotNullMethod .getDefinition() .getClassFileVersionOrElse(null)) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode(method -> new CheckNotZeroCode(checkNotNullMethod)) .setOptimizationInfo( checkNotNullMethod
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java index ddf8c42..ed8958d 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java
@@ -4,7 +4,6 @@ package com.android.tools.r8.ir.optimize.enums; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer; import com.android.tools.r8.cf.CfVersion; @@ -131,8 +130,8 @@ methodBuilder -> methodBuilder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode(codeGenerator) .setClassFileVersion(CfVersion.V1_6)); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java index 90d49ac..182b415 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.ir.optimize.enums; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; - import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.cf.code.CfArrayStore; import com.android.tools.r8.cf.code.CfConstNumber; @@ -149,8 +147,8 @@ methodBuilder -> methodBuilder .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .setCode(codeGenerator) .setClassFileVersion(CfVersion.V1_6)); } @@ -232,7 +230,7 @@ dexItemFactory.createField( sharedUtilityClassType, dexItemFactory.intArrayType, "$VALUES")) .setAccessFlags(FieldAccessFlags.createPublicStaticFinalSynthetic()) - .setApiLevel(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevel(appView.computedMinApiLevel()) .build(); fieldAccessInfoCollectionModifierBuilder .recordFieldReadInUnknownContext(valuesField.getReference()) @@ -249,8 +247,8 @@ .setAccessFlags(MethodAccessFlags.createForClassInitializer()) .setCode(createClassInitializerCode(sharedUtilityClassType, valuesField)) .setClassFileVersion(CfVersion.V1_6) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .build(); } @@ -295,8 +293,8 @@ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setCode(createValuesMethodCode(sharedUtilityClassType, valuesField)) .setClassFileVersion(CfVersion.V1_6) - .setApiLevelForDefinition(minApiLevelIfEnabledOrUnknown(appView)) - .setApiLevelForCode(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevelForDefinition(appView.computedMinApiLevel()) + .setApiLevelForCode(appView.computedMinApiLevel()) .build(); this.valuesMethod = valuesMethod; return valuesMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java index 27fa69a..5cb256c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.ir.optimize.library; import static com.android.tools.r8.graph.DexLibraryClass.asLibraryClassOrNull; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.graph.AppView; @@ -39,7 +38,7 @@ .setAccessFlags( FieldAccessFlags.fromCfAccessFlags( Constants.ACC_PRIVATE | Constants.ACC_FINAL)) - .setApiLevel(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevel(appView.computedMinApiLevel()) // Will be traced by the enqueuer. .disableAndroidApiLevelCheck() .build());
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java index 129acae..19bbe92 100644 --- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java +++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.shaking; import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; -import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; @@ -87,7 +86,7 @@ .dexItemFactory() .createField(clazz.type, clinitField.type, clinitField.name)) .setAccessFlags(accessFlags) - .setApiLevel(minApiLevelIfEnabledOrUnknown(appView)) + .setApiLevel(appView.computedMinApiLevel()) .build(); clazz.appendStaticField(encodedClinitField); }
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java index 941bcff..227cbf7 100644 --- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java +++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -7,6 +7,7 @@ import static com.android.tools.r8.ir.desugar.records.RecordRewriterHelper.isInvokeDynamicOnRecord; import com.android.tools.r8.androidapi.AndroidApiLevelCompute; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.code.CfOrDexInstruction; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; @@ -21,26 +22,25 @@ 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.utils.AndroidApiLevel; import java.util.ListIterator; public class DefaultEnqueuerUseRegistry extends UseRegistry<ProgramMethod> { protected final AppView<? extends AppInfoWithClassHierarchy> appView; protected final Enqueuer enqueuer; - private final AndroidApiLevelCompute computeApiLevel; - private AndroidApiLevel maxApiReferenceLevel; + private final AndroidApiLevelCompute apiLevelCompute; + private ComputedApiLevel maxApiReferenceLevel; public DefaultEnqueuerUseRegistry( AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context, Enqueuer enqueuer, - AndroidApiLevelCompute computeApiLevel) { + AndroidApiLevelCompute apiLevelCompute) { super(appView, context); this.appView = appView; this.enqueuer = enqueuer; - this.computeApiLevel = computeApiLevel; - this.maxApiReferenceLevel = appView.options().getMinApiLevel(); + this.apiLevelCompute = apiLevelCompute; + maxApiReferenceLevel = appView.computedMinApiLevel(); } public DexProgramClass getContextHolder() { @@ -223,14 +223,18 @@ if (reference.isDexMember()) { maxApiReferenceLevel = maxApiReferenceLevel.max( - computeApiLevel.computeApiLevelForDefinition( - reference.asDexMember(), appView.dexItemFactory())); + apiLevelCompute.computeApiLevelForDefinition( + reference.asDexMember(), + appView.dexItemFactory(), + apiLevelCompute.getPlatformApiLevelOrUnknown(appView))); } maxApiReferenceLevel = - maxApiReferenceLevel.max(computeApiLevel.computeApiLevelForLibraryReference(reference)); + maxApiReferenceLevel.max( + apiLevelCompute.computeApiLevelForLibraryReference( + reference, apiLevelCompute.getPlatformApiLevelOrUnknown(appView))); } - public AndroidApiLevel getMaxApiReferenceLevel() { + public ComputedApiLevel getMaxApiReferenceLevel() { return maxApiReferenceLevel; } }
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 c539364..9f30d38 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -502,7 +502,7 @@ liveFields = new LiveFieldsSet(graphReporter::registerField); apiLevelCompute = AndroidApiLevelCompute.create(appView); if (mode.isInitialTreeShaking()) { - desugaring = CfInstructionDesugaringCollection.create(appView, apiLevelCompute); + desugaring = CfInstructionDesugaringCollection.create(appView); interfaceProcessor = new InterfaceProcessor(appView); } else { desugaring = CfInstructionDesugaringCollection.empty();
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 4f116de..9396f50 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -8,7 +8,8 @@ import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT; import static com.android.tools.r8.ir.code.Invoke.Type.STATIC; -import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache; +import com.android.tools.r8.androidapi.AndroidApiLevelCompute; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; @@ -66,7 +67,6 @@ import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode; import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode; import com.android.tools.r8.logging.Log; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.CollectionUtils; import com.android.tools.r8.utils.FieldSignatureEquivalence; @@ -222,7 +222,7 @@ private final MethodPoolCollection methodPoolCollection; private final Timing timing; private Collection<DexMethod> invokes; - private final AndroidApiReferenceLevelCache apiReferenceLevelCache; + private final AndroidApiLevelCompute apiLevelCompute; private final OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance(); @@ -261,7 +261,7 @@ this.executorService = executorService; this.methodPoolCollection = new MethodPoolCollection(appView, subtypingInfo); this.lensBuilder = new VerticalClassMergerGraphLens.Builder(appView.dexItemFactory()); - this.apiReferenceLevelCache = AndroidApiReferenceLevelCache.create(appView); + this.apiLevelCompute = AndroidApiLevelCompute.create(appView); this.timing = timing; Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder(); @@ -531,11 +531,9 @@ // Only merge if api reference level of source class is equal to target class. The check is // somewhat expensive. if (appView.options().apiModelingOptions().enableApiCallerIdentification) { - AndroidApiLevel sourceApiLevel = - sourceClass.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax); - AndroidApiLevel targetApiLevel = - targetClass.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax); - if (sourceApiLevel != targetApiLevel) { + ComputedApiLevel sourceApiLevel = sourceClass.getApiReferenceLevel(appView, apiLevelCompute); + ComputedApiLevel targetApiLevel = targetClass.getApiReferenceLevel(appView, apiLevelCompute); + if (!sourceApiLevel.equals(targetApiLevel)) { if (Log.ENABLED) { AbortReason.API_REFERENCE_LEVEL.printLogMessageForClass(sourceClass); }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java index 56a9d20..0af4bf0 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -3,8 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.synthesis; -import static com.android.tools.r8.utils.AndroidApiLevel.NOT_SET; - +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.graph.Code; import com.android.tools.r8.graph.DexAnnotationSet; @@ -20,7 +19,6 @@ import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo; import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo; import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; -import com.android.tools.r8.utils.AndroidApiLevel; public class SyntheticMethodBuilder { @@ -39,8 +37,8 @@ private MethodTypeSignature genericSignature = MethodTypeSignature.noSignature(); private DexAnnotationSet annotations = DexAnnotationSet.empty(); private ParameterAnnotationsList parameterAnnotationsList = ParameterAnnotationsList.empty(); - private AndroidApiLevel apiLevelForDefinition = NOT_SET; - private AndroidApiLevel apiLevelForCode = NOT_SET; + private ComputedApiLevel apiLevelForDefinition = ComputedApiLevel.notSet(); + private ComputedApiLevel apiLevelForCode = ComputedApiLevel.notSet(); private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance(); private boolean checkAndroidApiLevels = true; @@ -109,12 +107,12 @@ return this; } - public SyntheticMethodBuilder setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) { + public SyntheticMethodBuilder setApiLevelForDefinition(ComputedApiLevel apiLevelForDefinition) { this.apiLevelForDefinition = apiLevelForDefinition; return this; } - public SyntheticMethodBuilder setApiLevelForCode(AndroidApiLevel apiLevelForCode) { + public SyntheticMethodBuilder setApiLevelForCode(ComputedApiLevel apiLevelForCode) { this.apiLevelForCode = apiLevelForCode; return this; }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java index 6b82664..38934f2 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -4,7 +4,6 @@ package com.android.tools.r8.utils; import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.AppView; import com.android.tools.r8.utils.structural.Ordered; import java.util.Arrays; import java.util.List; @@ -43,9 +42,7 @@ R(30), S(31), Sv2(32), - ANDROID_PLATFORM(10000), - UNKNOWN(10001), - NOT_SET(10002); + ANDROID_PLATFORM(10000); // When updating LATEST and a new version goes stable, add a new api-versions.xml to third_party // and update the version and generated jar in AndroidApiDatabaseBuilderGeneratorTest. @@ -78,13 +75,6 @@ return DexVersion.getDexVersion(this); } - public static AndroidApiLevel minApiLevelIfEnabledOrUnknown(AppView<?> appView) { - InternalOptions options = appView.options(); - return options.apiModelingOptions().enableApiCallerIdentification - ? options.getMinApiLevel() - : UNKNOWN; - } - public static List<AndroidApiLevel> getAndroidApiLevelsSorted() { return Arrays.asList(AndroidApiLevel.values()); }
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 c4a7396..73cf09f 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.utils; import com.android.tools.r8.androidapi.AndroidApiLevelCompute; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.graph.LibraryMethod; import com.android.tools.r8.graph.ProgramMethod; @@ -15,10 +16,6 @@ if (!options.apiModelingOptions().enableApiCallerIdentification) { return true; } - if (options.isAndroidPlatform()) { - // Don't disable inlining in the Android platform based on the Api database. - return true; - } if (caller.getHolderType() == inlinee.getHolderType()) { return true; } @@ -32,12 +29,13 @@ LibraryMethod method, AndroidApiLevelCompute androidApiLevelCompute, InternalOptions options) { - AndroidApiLevel apiLevel = - androidApiLevelCompute.computeApiLevelForLibraryReference(method.getReference()); - if (apiLevel == AndroidApiLevel.UNKNOWN) { + ComputedApiLevel apiLevel = + androidApiLevelCompute.computeApiLevelForLibraryReference( + method.getReference(), ComputedApiLevel.unknown()); + if (apiLevel.isUnknownApiLevel()) { return false; } assert options.apiModelingOptions().enableApiCallerIdentification; - return apiLevel.isLessThanOrEqualTo(options.getMinApiLevel()); + return apiLevel.asKnownApiLevel().getApiLevel().isLessThanOrEqualTo(options.getMinApiLevel()); } }
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java index a807bba..624e70e 100644 --- a/src/main/java/com/android/tools/r8/utils/DexVersion.java +++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -77,7 +77,6 @@ case L_MR1: case M: return DexVersion.V35; - case UNKNOWN: default: throw new Unreachable("Unsupported api level " + androidApiLevel); }
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 ea7c922..1cbbc21 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.utils; +import static com.android.tools.r8.utils.AndroidApiLevel.ANDROID_PLATFORM; + import com.android.tools.r8.ClassFileConsumer; import com.android.tools.r8.CompilationMode; import com.android.tools.r8.DataResourceConsumer; @@ -17,6 +19,7 @@ import com.android.tools.r8.StringConsumer; import com.android.tools.r8.Version; import com.android.tools.r8.androidapi.AndroidApiForHashingClass; +import com.android.tools.r8.androidapi.ComputedApiLevel; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.dex.Marker; import com.android.tools.r8.dex.Marker.Backend; @@ -424,7 +427,7 @@ } public boolean isAndroidPlatform() { - return minApiLevel == AndroidApiLevel.ANDROID_PLATFORM; + return minApiLevel == ANDROID_PLATFORM; } public boolean isDesugaredLibraryCompilation() { @@ -564,7 +567,6 @@ public void setMinApiLevel(AndroidApiLevel minApiLevel) { assert minApiLevel != null; - assert minApiLevel.isLessThan(AndroidApiLevel.UNKNOWN); this.minApiLevel = minApiLevel; } @@ -1470,7 +1472,7 @@ public Map<MethodReference, AndroidApiLevel> methodApiMapping = new HashMap<>(); public Map<FieldReference, AndroidApiLevel> fieldApiMapping = new HashMap<>(); public Map<ClassReference, AndroidApiLevel> classApiMapping = new HashMap<>(); - public BiConsumer<MethodReference, AndroidApiLevel> tracedMethodApiLevelCallback = null; + public BiConsumer<MethodReference, ComputedApiLevel> tracedMethodApiLevelCallback = null; public boolean enableApiCallerIdentification = true; public boolean checkAllApiReferencesAreSet = true; @@ -1498,7 +1500,7 @@ @Override public AndroidApiLevel getApiLevel() { - return classApiMapping.getOrDefault(classReference, AndroidApiLevel.UNKNOWN); + return classApiMapping.getOrDefault(classReference, ANDROID_PLATFORM); } @Override
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java index 53886e2..2d0cc12 100644 --- a/src/test/java/com/android/tools/r8/ToolHelper.java +++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -867,8 +867,6 @@ case J_MR2: case K_WATCH: case ANDROID_PLATFORM: - case UNKNOWN: - case NOT_SET: return false; default: return true;
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java index d7db635..300eed5 100644 --- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java +++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java
@@ -103,8 +103,7 @@ for (int i = 0; i < integers.size(); i++) { indices[i] = integers.get(i); AndroidApiLevel androidApiLevel = apiLevelMap.get(integers.get(i)); - apiLevel[i] = - (byte) (androidApiLevel == AndroidApiLevel.NOT_SET ? -1 : androidApiLevel.getLevel()); + apiLevel[i] = (byte) (androidApiLevel == null ? -1 : androidApiLevel.getLevel()); } try (FileOutputStream fileOutputStream = new FileOutputStream(pathToIndices.toFile()); @@ -160,7 +159,7 @@ return ((reference, apiLevel) -> { AndroidApiLevel existingMethod = apiLevelMap.put(reference.hashCode(), apiLevel); if (existingMethod != null) { - apiLevelMap.put(reference.hashCode(), AndroidApiLevel.NOT_SET); + apiLevelMap.put(reference.hashCode(), null); Pair<DexReference, AndroidApiLevel> existingPair = reverseMap.get(reference.hashCode()); addAmbiguousEntry(existingPair.getSecond(), existingPair.getFirst(), ambiguousMap); addAmbiguousEntry(apiLevel, reference, ambiguousMap);
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java index 88d53c1..9bbc751 100644 --- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
@@ -126,7 +126,7 @@ AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL); DexItemFactory factory = new DexItemFactory(); AndroidApiLevelHashingDatabaseImpl androidApiLevelDatabase = - new AndroidApiLevelHashingDatabaseImpl(factory, ImmutableList.of()); + new AndroidApiLevelHashingDatabaseImpl(ImmutableList.of()); parsedApiClasses.forEach( parsedApiClass -> { DexType type = factory.createType(parsedApiClass.getClassReference().getDescriptor()); @@ -137,9 +137,13 @@ methodReferences.forEach( methodReference -> { DexMethod method = factory.createMethod(methodReference); - androidApiLevelDatabase - .getMethodApiLevel(method) - .isLessThanOrEqualTo(methodApiLevel); + AndroidApiLevel androidApiLevel; + if (factory.objectMembers.isObjectMember(method)) { + androidApiLevel = AndroidApiLevel.B; + } else { + androidApiLevel = androidApiLevelDatabase.getMethodApiLevel(method); + } + androidApiLevel.isLessThanOrEqualTo(methodApiLevel); })); parsedApiClass.visitFieldReferences( (fieldApiLevel, fieldReferences) ->
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java index c87f2cc..d4127e8 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
@@ -63,15 +63,22 @@ } public static class AccessibilityNodeInfo$AccessibilityAction { + + private int i; + + public AccessibilityNodeInfo$AccessibilityAction(int i, CharSequence sequence) { + this.i = i; + } + int describeContents() { - return 42; + return i; } } public static class Main { public static void main(String[] args) { - new AccessibilityNodeInfo$AccessibilityAction().describeContents(); + new AccessibilityNodeInfo$AccessibilityAction(42, "foobar").describeContents(); } } }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java index 8e5cc58..c8ee027 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -7,6 +7,7 @@ import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; import com.android.tools.r8.TestCompilerBuilder; import com.android.tools.r8.TestParameters; @@ -42,7 +43,7 @@ public static <T extends TestCompilerBuilder<?, ?, ?, ?, ?>> ThrowableConsumer<T> setMockApiLevelForMethod( - Constructor constructor, AndroidApiLevel apiLevel) { + Constructor<?> constructor, AndroidApiLevel apiLevel) { return compilerBuilder -> { compilerBuilder.addOptionsModification( options -> { @@ -118,7 +119,12 @@ return compilerBuilder -> { compilerBuilder.addOptionsModification( options -> { - options.apiModelingOptions().tracedMethodApiLevelCallback = consumer; + options.apiModelingOptions().tracedMethodApiLevelCallback = + (methodReference, computedApiLevel) -> { + assertTrue(computedApiLevel.isKnownApiLevel()); + consumer.accept( + methodReference, computedApiLevel.asKnownApiLevel().getApiLevel()); + }; }); }; }
diff --git a/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java b/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java index 86ccd24..51bd0cf 100644 --- a/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java +++ b/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java
@@ -189,7 +189,7 @@ new DataResourceConsumerForTesting(options.dataResourceConsumer); options.dataResourceConsumer = dataResourceConsumer; }) - .setMinApi(parameters.getRuntime()) + .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), OtherTestClass.class) .assertSuccessWithOutput(expectedOutput) .inspector();