blob: 98c8bd2c7bffe6cd63f702adb2de2c8586d92f0d [file] [log] [blame]
// Copyright (c) 2019, 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.graph;
import static com.android.tools.r8.ir.optimize.info.OptimizationFeedback.getSimpleFeedback;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
import com.android.tools.r8.logging.Log;
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
implements ProgramMember<DexEncodedMethod, DexMethod> {
public ProgramMethod(DexProgramClass holder, DexEncodedMethod method) {
super(holder, method);
}
public IRCode buildIR(AppView<?> appView) {
DexEncodedMethod method = getDefinition();
return method.hasCode() ? method.getCode().buildIR(this, appView, getOrigin()) : null;
}
public IRCode buildInliningIR(
ProgramMethod context,
AppView<?> appView,
NumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
MethodProcessor methodProcessor) {
Code code = getDefinition().getCode();
GraphLens codeLens = appView.graphLens();
RewrittenPrototypeDescription protoChanges = RewrittenPrototypeDescription.none();
if (methodProcessor.shouldApplyCodeRewritings(this)) {
codeLens = appView.codeLens();
protoChanges = appView.graphLens().lookupPrototypeChangesForMethodDefinition(getReference());
}
return code.buildInliningIR(
context,
this,
appView,
codeLens,
valueNumberGenerator,
callerPosition,
origin,
protoChanges);
}
public void collectIndexedItems(
IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) {
DexEncodedMethod definition = getDefinition();
assert !definition.isObsolete();
assert !definition.hasCode() || definition.getCode().isDexCode();
getReference().collectIndexedItems(indexedItems);
Code code = definition.getCode();
if (code != null && code.isDexCode()) {
code.asDexCode().collectIndexedItems(indexedItems, this, graphLens, rewriter);
}
definition.annotations().collectIndexedItems(indexedItems);
definition.parameterAnnotationsList.collectIndexedItems(indexedItems);
}
public boolean canBeConvertedToAbstractMethod(AppView<AppInfoWithLiveness> appView) {
return (appView.options().canUseAbstractMethodOnNonAbstractClass()
|| getHolder().isAbstract()
|| getHolder().isInterface())
&& !getAccessFlags().isNative()
&& !getAccessFlags().isPrivate()
&& !getAccessFlags().isStatic()
&& !appView.appInfo().isFailedResolutionTarget(getReference());
}
public void convertToAbstractOrThrowNullMethod(AppView<AppInfoWithLiveness> appView) {
if (!convertToAbstractMethodIfPossible(appView)) {
convertToThrowNullMethod(appView);
}
}
private boolean convertToAbstractMethodIfPossible(AppView<AppInfoWithLiveness> appView) {
boolean canBeAbstract = canBeConvertedToAbstractMethod(appView);
if (canBeAbstract) {
MethodAccessFlags accessFlags = getAccessFlags();
accessFlags.demoteFromFinal();
accessFlags.demoteFromStrict();
accessFlags.demoteFromSynchronized();
accessFlags.promoteToAbstract();
getDefinition().clearApiLevelForCode(appView);
getDefinition().unsetCode();
getSimpleFeedback().unsetOptimizationInfoForAbstractMethod(this);
}
return canBeAbstract;
}
public void convertToThrowNullMethod(AppView<?> appView) {
MethodAccessFlags accessFlags = getAccessFlags();
accessFlags.demoteFromAbstract();
Code emptyThrowingCode = getDefinition().buildEmptyThrowingCode(appView.options());
getDefinition().setApiLevelForCode(AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView));
getDefinition().setCode(emptyThrowingCode, appView);
getSimpleFeedback().markProcessed(getDefinition(), ConstraintWithTarget.ALWAYS);
getSimpleFeedback().unsetOptimizationInfoForThrowNullMethod(this);
}
public void registerCodeReferences(UseRegistry<?> registry) {
Code code = getDefinition().getCode();
if (code != null) {
if (Log.ENABLED) {
Log.verbose(getClass(), "Registering definitions reachable from `%s`.", this);
}
code.registerCodeReferences(this, registry);
}
}
public <R> R registerCodeReferencesWithResult(UseRegistryWithResult<R, ?> registry) {
registerCodeReferences(registry);
return registry.getResult();
}
@Override
public ProgramMethod getContext() {
return this;
}
@Override
public DexProgramClass getContextClass() {
return getHolder();
}
@Override
public boolean isProgramMember() {
return true;
}
@Override
public ProgramMethod asProgramMember() {
return this;
}
@Override
public boolean isProgramMethod() {
return true;
}
@Override
public ProgramMethod asMethod() {
return this;
}
@Override
public ProgramMethod asProgramMethod() {
return this;
}
@Override
public DexProgramClass getHolder() {
DexClass holder = super.getHolder();
assert holder.isProgramClass();
return holder.asProgramClass();
}
@Override
public KotlinMethodLevelInfo getKotlinInfo() {
return getDefinition().getKotlinInfo();
}
public MethodPosition getPosition() {
return getDefinition().getPosition();
}
}