blob: 376acee6b7530ef677c61735adc1c3ebcd0b455a [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.features;
import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration;
import com.android.tools.r8.features.diagnostic.IllegalAccessWithIsolatedFeatureSplitsDiagnostic;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.analysis.EnqueuerFieldAccessAnalysis;
import com.android.tools.r8.graph.analysis.EnqueuerInvokeAnalysis;
import com.android.tools.r8.graph.analysis.EnqueuerTypeAccessAnalysis;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.utils.InternalOptions;
// TODO(b/300247439): Also trace types referenced from new-array instructions, call sites, etc.
public class IsolatedFeatureSplitsChecker
implements EnqueuerFieldAccessAnalysis, EnqueuerInvokeAnalysis, EnqueuerTypeAccessAnalysis {
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final ClassToFeatureSplitMap features;
private IsolatedFeatureSplitsChecker(AppView<? extends AppInfoWithClassHierarchy> appView) {
this.appView = appView;
this.features = appView.appInfo().getClassToFeatureSplitMap();
}
public static void register(
AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
if (enabled(appView)) {
IsolatedFeatureSplitsChecker checker = new IsolatedFeatureSplitsChecker(appView);
enqueuer
.registerFieldAccessAnalysis(checker)
.registerInvokeAnalysis(checker)
.registerTypeAccessAnalysis(checker);
}
}
private static boolean enabled(AppView<? extends AppInfoWithClassHierarchy> appView) {
InternalOptions options = appView.options();
return options.hasFeatureSplitConfiguration()
&& options.getFeatureSplitConfiguration().isIsolatedSplitsEnabled();
}
private void traceFieldAccess(FieldResolutionResult resolutionResult, ProgramMethod context) {
ProgramField resolvedField = resolutionResult.getSingleProgramField();
if (resolvedField != null) {
checkAccess(resolvedField, context);
checkAccess(resolutionResult.getInitialResolutionHolder().asProgramClass(), context);
}
}
private void traceMethodInvoke(MethodResolutionResult resolutionResult, ProgramMethod context) {
ProgramMethod resolvedMethod = resolutionResult.getResolvedProgramMethod();
if (resolvedMethod != null) {
checkAccess(resolvedMethod, context);
checkAccess(resolutionResult.getInitialResolutionHolder().asProgramClass(), context);
}
}
private void traceTypeAccess(DexClass clazz, ProgramMethod context) {
if (clazz != null && clazz.isProgramClass()) {
checkAccess(clazz.asProgramClass(), context);
}
}
private void checkAccess(ProgramDefinition accessedItem, ProgramMethod context) {
if (accessedItem.getAccessFlags().isPublic()
|| features.isInSameFeature(accessedItem, context, appView)) {
return;
}
if (accessedItem.getAccessFlags().isProtected()
&& appView.appInfo().isSubtype(context.getContextClass(), accessedItem.getContextClass())) {
return;
}
DontWarnConfiguration dontWarnConfiguration = appView.getDontWarnConfiguration();
if (dontWarnConfiguration.matches(accessedItem) || dontWarnConfiguration.matches(context)) {
return;
}
appView
.reporter()
.error(new IllegalAccessWithIsolatedFeatureSplitsDiagnostic(accessedItem, context));
}
// Field accesses.
@Override
public void traceInstanceFieldRead(
DexField field,
FieldResolutionResult resolutionResult,
ProgramMethod context,
EnqueuerWorklist worklist) {
traceFieldAccess(resolutionResult, context);
}
@Override
public void traceInstanceFieldWrite(
DexField field,
FieldResolutionResult resolutionResult,
ProgramMethod context,
EnqueuerWorklist worklist) {
traceFieldAccess(resolutionResult, context);
}
@Override
public void traceStaticFieldRead(
DexField field,
SingleFieldResolutionResult<?> resolutionResult,
ProgramMethod context,
EnqueuerWorklist worklist) {
traceFieldAccess(resolutionResult, context);
}
@Override
public void traceStaticFieldWrite(
DexField field,
FieldResolutionResult resolutionResult,
ProgramMethod context,
EnqueuerWorklist worklist) {
traceFieldAccess(resolutionResult, context);
}
// Method invokes.
@Override
public void traceInvokeStatic(
DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
traceMethodInvoke(resolutionResult, context);
}
@Override
public void traceInvokeDirect(
DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
traceMethodInvoke(resolutionResult, context);
}
@Override
public void traceInvokeInterface(
DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
traceMethodInvoke(resolutionResult, context);
}
@Override
public void traceInvokeSuper(
DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
traceMethodInvoke(resolutionResult, context);
}
@Override
public void traceInvokeVirtual(
DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
traceMethodInvoke(resolutionResult, context);
}
// Type accesses.
@Override
public void traceCheckCast(DexType type, DexClass clazz, ProgramMethod context) {
traceTypeAccess(clazz, context);
}
@Override
public void traceSafeCheckCast(DexType type, DexClass clazz, ProgramMethod context) {
traceTypeAccess(clazz, context);
}
@Override
public void traceConstClass(DexType type, DexClass clazz, ProgramMethod context) {
traceTypeAccess(clazz, context);
}
@Override
public void traceExceptionGuard(DexType type, DexClass clazz, ProgramMethod context) {
traceTypeAccess(clazz, context);
}
@Override
public void traceInstanceOf(DexType type, DexClass clazz, ProgramMethod context) {
traceTypeAccess(clazz, context);
}
@Override
public void traceNewInstance(DexType type, DexClass clazz, ProgramMethod context) {
traceTypeAccess(clazz, context);
}
}