blob: 21a7635703a88d599df29422d384ae264174f108 [file] [log] [blame]
// Copyright (c) 2023, 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.profile.art;
import static com.android.tools.r8.profile.art.ArtProfileCompletenessChecker.CompletenessExceptions.ALLOW_MISSING_ENUM_UNBOXING_UTILITY_METHODS;
import com.android.tools.r8.graph.AppView;
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.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class ArtProfileCompletenessChecker {
public enum CompletenessExceptions {
ALLOW_MISSING_ENUM_UNBOXING_UTILITY_METHODS
}
public static boolean verify(
AppView<?> appView, CompletenessExceptions... completenessExceptions) {
if (appView.options().getArtProfileOptions().isCompletenessCheckForTestingEnabled()) {
ArtProfile completeArtProfile = appView.getArtProfileCollection().asNonEmpty().getLast();
assert verifyProfileIsComplete(
appView, completeArtProfile, Sets.newHashSet(completenessExceptions));
}
return true;
}
private static boolean verifyProfileIsComplete(
AppView<?> appView,
ArtProfile artProfile,
Set<CompletenessExceptions> completenessExceptions) {
assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
List<DexReference> missing = new ArrayList<>();
for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) {
if (appView.horizontallyMergedClasses().hasBeenMergedIntoDifferentType(clazz.getType())
|| (appView.hasVerticallyMergedClasses()
&& appView.verticallyMergedClasses().hasBeenMergedIntoSubtype(clazz.getType()))
|| appView.unboxedEnums().isUnboxedEnum(clazz)) {
continue;
}
if (!artProfile.containsClassRule(clazz.getType())) {
recordMissingDefinition(appView, clazz, completenessExceptions, missing);
}
for (ProgramMethod method : clazz.programMethods()) {
if (!artProfile.containsMethodRule(method.getReference())) {
recordMissingDefinition(appView, method, completenessExceptions, missing);
}
}
}
if (!missing.isEmpty()) {
String message =
StringUtils.join(System.lineSeparator(), missing, DexReference::toSmaliString);
assert false : message;
}
return true;
}
private static void recordMissingDefinition(
AppView<?> appView,
ProgramDefinition definition,
Set<CompletenessExceptions> completenessExceptions,
List<DexReference> missing) {
if (completenessExceptions.contains(ALLOW_MISSING_ENUM_UNBOXING_UTILITY_METHODS)) {
DexType contextType = definition.getContextType();
SyntheticItems syntheticItems = appView.getSyntheticItems();
if (syntheticItems.isSynthetic(contextType)) {
if (syntheticItems.isSyntheticOfKind(
contextType, naming -> naming.ENUM_UNBOXING_CHECK_NOT_ZERO_METHOD)
|| syntheticItems.isSyntheticOfKind(
contextType, naming -> naming.ENUM_UNBOXING_LOCAL_UTILITY_CLASS)
|| syntheticItems.isSyntheticOfKind(
contextType, naming -> naming.ENUM_UNBOXING_SHARED_UTILITY_CLASS)) {
return;
}
}
}
missing.add(definition.getReference());
}
}