blob: f9418b4a7fbcf6ab509b1d31b0c246edfbde34b7 [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.ir.optimize.inliner;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.InstancePut;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.utils.StringUtils;
import java.io.PrintStream;
import java.util.Set;
class WhyAreYouNotInliningReporterImpl extends WhyAreYouNotInliningReporter {
private final ProgramMethod callee;
private final ProgramMethod context;
private final PrintStream output;
private boolean reasonHasBeenReported = false;
WhyAreYouNotInliningReporterImpl(
ProgramMethod callee, ProgramMethod context, PrintStream output) {
this.callee = callee;
this.context = context;
this.output = output;
}
private void print(String reason) {
output.print("Method `");
output.print(callee.toSourceString());
output.print("` was not inlined into `");
output.print(context.toSourceString());
if (reason != null) {
output.print("`: ");
output.println(reason);
} else {
output.println("`.");
}
reasonHasBeenReported = true;
}
private void printWithExceededThreshold(
String reason, String description, int value, int threshold) {
print(reason + " (" + description + ": " + value + ", threshold: " + threshold + ").");
}
@Override
public void reportExtraNeverInline() {
print("method is marked as an additional never inline method.");
}
@Override
public void reportCallerNotSameClass() {
print("inlinee can only be inlined into methods in the same class.");
}
@Override
public void reportCallerNotSameNest() {
print("inlinee can only be inlined into methods in the same class (and its nest members).");
}
@Override
public void reportCallerNotSamePackage() {
print(
"inlinee can only be inlined into methods in the same package "
+ "(declared package private or accesses package private type or member).");
}
@Override
public void reportCallerNotSubtype() {
print(
"inlinee can only be inlined into methods in the same package and methods in subtypes of "
+ "the inlinee's enclosing class"
+ "(declared protected or accesses protected type or member).");
}
@Override
public void reportClasspathMethod() {
print("inlinee is on the classpath.");
}
@Override
public void reportInaccessible() {
print("inlinee is not accessible from the caller context.");
}
@Override
public void reportIncorrectArity(int numberOfArguments, int arity) {
print(
"number of arguments ("
+ numberOfArguments
+ ") does not match arity of method ("
+ arity
+ ").");
}
@Override
public void reportInlineeDoesNotHaveCode() {
print("inlinee does not have code.");
}
@Override
public void reportInlineeNotInliningCandidate() {
print("unsupported instruction in inlinee.");
}
@Override
public void reportInlineeNotProcessed() {
print("inlinee not processed yet.");
}
@Override
public void reportInlineeNotSimple() {
print(
"not inlining due to code size heuristic "
+ "(inlinee may have multiple callers and is not considered trivial).");
}
@Override
public void reportInlineeHigherApiCall() {
print("inlinee having a higher api call than caller context.");
}
@Override
public void reportInlineeRefersToClassesNotInMainDex() {
print(
"inlining could increase the main dex size "
+ "(caller is in main dex and inlinee refers to classes not in main dex).");
}
@Override
public void reportInliningAcrossFeatureSplit() {
print("cannot inline across feature splits.");
}
@Override
public void reportInstructionBudgetIsExceeded() {
print("caller's instruction budget is exceeded.");
}
@Override
public void reportInvalidDoubleInliningCandidate() {
print("inlinee is invoked more than once and could not be inlined into all call sites.");
}
@Override
public void reportInvalidInliningReason(Reason reason, Set<Reason> validInliningReasons) {
print(
"not a valid inlining reason (was: "
+ reason
+ ", allowed: one of "
+ StringUtils.join(", ", validInliningReasons)
+ ").");
}
@Override
public void reportLibraryMethod() {
print("inlinee is a library method.");
}
@Override
public void reportMarkedAsNeverInline() {
print("method is marked by a -neverinline rule.");
}
@Override
public void reportMustTriggerClassInitialization() {
print(
"cannot guarantee that the enclosing class of the inlinee is guaranteed to be class "
+ "initialized before the first side-effecting instruction in the inlinee.");
}
@Override
public void reportNoInliningIntoConstructorsWhenGeneratingClassFiles() {
print("inlining into constructors not supported when generating class files.");
}
@Override
public void reportPinned() {
print("method is kept by a Proguard configuration rule.");
}
@Override
public void reportPotentialExplosionInExceptionalControlFlowResolutionBlocks(
int estimatedNumberOfControlFlowResolutionBlocks, int threshold) {
printWithExceededThreshold(
"could lead to an explosion in the number of moves due to the exceptional control flow",
"estimated number of control flow resolution blocks",
estimatedNumberOfControlFlowResolutionBlocks,
threshold);
}
@Override
public void reportProcessedConcurrently() {
print(
"could lead to nondeterministic output since the inlinee is being optimized concurrently.");
}
@Override
public void reportReceiverDefinitelyNull() {
print("the receiver is always null at the call site.");
}
@Override
public void reportReceiverMaybeNull() {
print("the receiver may be null at the call site.");
}
@Override
public void reportRecursiveMethod() {
print("recursive calls are not inlined.");
}
@Override
public void reportUnknownTarget() {
print("could not find a single target.");
}
@Override
public void reportUnsafeConstructorInliningDueToFinalFieldAssignment(InstancePut instancePut) {
print(
"final field `"
+ instancePut.getField()
+ "` must be initialized in a constructor of `"
+ callee.getHolderType().toSourceString()
+ "`.");
}
@Override
public void reportUnsafeConstructorInliningDueToIndirectConstructorCall(InvokeDirect invoke) {
print(
"must invoke a constructor from the class being instantiated (would invoke `"
+ invoke.getInvokedMethod().toSourceString()
+ "`).");
}
@Override
public void reportUnsafeConstructorInliningDueToUninitializedObjectUse(Instruction user) {
print("would lead to use of uninitialized object (user: `" + user.toString() + "`).");
}
@Override
public void reportWillExceedInstructionBudget(int numberOfInstructions, int threshold) {
printWithExceededThreshold(
"would exceed the caller's instruction budget",
"number of instructions in inlinee",
numberOfInstructions,
threshold);
}
@Override
public void reportWillExceedMaxInliningDepth(int actualInliningDepth, int threshold) {
printWithExceededThreshold(
"would exceed the maximum inlining depth",
"current inlining depth",
actualInliningDepth,
threshold);
}
@Override
public void reportWillExceedMonitorEnterValuesBudget(
int numberOfMonitorEnterValuesAfterInlining, int threshold) {
printWithExceededThreshold(
"could negatively impact register allocation due to the number of monitor instructions",
"estimated number of locks after inlining",
numberOfMonitorEnterValuesAfterInlining,
threshold);
}
@Override
public boolean unsetReasonHasBeenReportedFlag() {
assert reasonHasBeenReported;
reasonHasBeenReported = false;
return true;
}
}