blob: 3568c170034f9fcb6b383a1147bd4d939e4706a3 [file] [log] [blame]
// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.horizontalclassmerging.policies;
import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.dex.code.CfOrDexInstruction;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
import com.android.tools.r8.synthesis.SyntheticItems;
import java.util.ListIterator;
public class ComputeApiLevelOfSyntheticClass extends SingleClassPolicy {
private final AppView<?> appView;
private final SyntheticItems syntheticItems;
public ComputeApiLevelOfSyntheticClass(AppView<?> appView) {
this.appView = appView;
this.syntheticItems = appView.getSyntheticItems();
}
@Override
public boolean canMerge(DexProgramClass clazz) {
assert syntheticItems.isSyntheticClass(clazz);
clazz.forEachProgramMethod(
programMethod -> {
DexEncodedMethod definition = programMethod.getDefinition();
if (definition.getApiLevelForCode().isNotSetApiLevel()) {
ComputeApiLevelUseRegistry computeApiLevel =
new ComputeApiLevelUseRegistry(appView, programMethod, appView.apiLevelCompute());
computeApiLevel.accept(programMethod);
ComputedApiLevel maxApiReferenceLevel = computeApiLevel.getMaxApiReferenceLevel();
assert !maxApiReferenceLevel.isNotSetApiLevel();
definition.setApiLevelForCode(maxApiReferenceLevel);
definition.setApiLevelForDefinition(computeApiLevel.getMaxApiReferenceLevel());
}
});
return true;
}
@Override
public String getName() {
return "ComputeApiLevelOfSyntheticClass";
}
private static class ComputeApiLevelUseRegistry extends UseRegistry<ProgramMethod> {
private final AppView<?> appView;
private final AndroidApiLevelCompute apiLevelCompute;
private ComputedApiLevel maxApiReferenceLevel;
public ComputeApiLevelUseRegistry(
AppView<?> appView, ProgramMethod context, AndroidApiLevelCompute apiLevelCompute) {
super(appView, context);
this.appView = appView;
this.apiLevelCompute = apiLevelCompute;
maxApiReferenceLevel = appView.computedMinApiLevel();
}
@Override
public void registerInitClass(DexType clazz) {
assert false : "Unexpected call to an instruction that should not exist on DEX";
}
@Override
public void registerRecordFieldValues(DexField[] fields) {
assert false : "Unexpected call to an instruction that should not exist on DEX";
}
@Override
public void registerInvokeVirtual(DexMethod invokedMethod) {
setMaxApiReferenceLevel(invokedMethod);
}
@Override
public void registerInvokeDirect(DexMethod invokedMethod) {
setMaxApiReferenceLevel(invokedMethod);
}
@Override
public void registerInvokeStatic(DexMethod invokedMethod) {
setMaxApiReferenceLevel(invokedMethod);
}
@Override
public void registerInvokeInterface(DexMethod invokedMethod) {
setMaxApiReferenceLevel(invokedMethod);
}
@Override
public void registerInvokeSuper(DexMethod invokedMethod) {
setMaxApiReferenceLevel(invokedMethod);
}
@Override
public void registerInstanceFieldRead(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerInstanceFieldReadFromMethodHandle(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerInstanceFieldWrite(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerInstanceFieldWriteFromMethodHandle(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerNewInstance(DexType type) {
setMaxApiReferenceLevel(type);
}
@Override
public void registerStaticFieldRead(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerStaticFieldReadFromMethodHandle(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerStaticFieldWrite(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerStaticFieldWriteFromMethodHandle(DexField field) {
setMaxApiReferenceLevel(field);
}
@Override
public void registerConstClass(
DexType type,
ListIterator<? extends CfOrDexInstruction> iterator,
boolean ignoreCompatRules) {
// Intentionally empty.
}
@Override
public void registerCheckCast(DexType type, boolean ignoreCompatRules) {
// Intentionally empty.
}
@Override
public void registerSafeCheckCast(DexType type) {
// Intentionally empty.
}
@Override
public void registerTypeReference(DexType type) {
// Intentionally empty.
}
@Override
public void registerInstanceOf(DexType type) {
// Intentionally empty.
}
@Override
public void registerExceptionGuard(DexType guard) {
setMaxApiReferenceLevel(guard);
}
@Override
public void registerMethodHandle(DexMethodHandle methodHandle, MethodHandleUse use) {
assert false : "Unexpected call to an instruction that should not exist on DEX";
}
@Override
public void registerCallSite(DexCallSite callSite) {
assert false : "Unexpected call to an instruction that should not exist on DEX";
}
private void setMaxApiReferenceLevel(DexReference reference) {
maxApiReferenceLevel =
maxApiReferenceLevel.max(
apiLevelCompute.computeApiLevelForLibraryReference(
reference, apiLevelCompute.getPlatformApiLevelOrUnknown(appView)));
}
public ComputedApiLevel getMaxApiReferenceLevel() {
return maxApiReferenceLevel;
}
}
}