Added inlining reason to InlineAction.

BUG=

Change-Id: I93658b52bccc050dab669af4843578d08880630f
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 188440d..965d770 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -22,7 +22,7 @@
 import com.android.tools.r8.ir.code.MoveType;
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
 import com.android.tools.r8.ir.synthetic.SynthesizedCode;
@@ -102,7 +102,7 @@
     return compilationState == PROCESSED_INLINING_CANDIDATE_PUBLIC;
   }
 
-  public void markProcessed(InliningConstraint state) {
+  public void markProcessed(Constraint state) {
     switch (state) {
       case ALWAYS:
         compilationState = PROCESSED_INLINING_CANDIDATE_PUBLIC;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java
index 94c415e..94f6507 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Argument.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.utils.InternalOptions;
 
 /**
@@ -67,7 +67,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Binop.java b/src/main/java/com/android/tools/r8/ir/code/Binop.java
index 83240bb..899516a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Binop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Binop.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 public abstract class Binop extends Instruction {
 
@@ -112,7 +112,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 451832f..4cca9dd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -15,7 +15,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.utils.NumberUtils;
 
 public class ConstNumber extends ConstInstruction {
@@ -188,7 +188,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Div.java b/src/main/java/com/android/tools/r8/ir/code/Div.java
index c8c1c32..8fd9bf0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Div.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Div.java
@@ -14,9 +14,6 @@
 import com.android.tools.r8.code.DivIntLit8;
 import com.android.tools.r8.code.DivLong;
 import com.android.tools.r8.code.DivLong2Addr;
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
 
 public class Div extends ArithmeticBinop {
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index ba1e0e9..0b8d876 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -9,8 +9,7 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.Inliner;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import java.util.List;
 
 abstract class FieldInstruction extends Instruction {
@@ -43,7 +42,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
     // Resolve the field if possible and decide whether the instruction can inlined.
     DexType fieldHolder = field.getHolder();
     DexEncodedField target = info.lookupInstanceTarget(fieldHolder, field);
@@ -51,15 +50,15 @@
     if ((target != null) && (fieldClass != null) && !fieldClass.isLibraryClass()) {
       DexAccessFlags flags = target.accessFlags;
       if (flags.isPublic()) {
-        return Inliner.InliningConstraint.ALWAYS;
+        return Constraint.ALWAYS;
       }
       if (flags.isPrivate() && (fieldHolder == holder)) {
-        return Inliner.InliningConstraint.PRIVATE;
+        return Constraint.PRIVATE;
       }
       if (flags.isProtected() && (fieldHolder.isSamePackage(holder))) {
-        return Inliner.InliningConstraint.PACKAGE;
+        return Constraint.PACKAGE;
       }
     }
-    return Inliner.InliningConstraint.NEVER;
+    return Constraint.NEVER;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
index 3fe498d..1126299 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 public class InstanceOf extends Instruction {
 
@@ -75,14 +75,14 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
     DexClass targetClass = info.definitionFor(type());
     if (targetClass == null) {
-      return InliningConstraint.NEVER;
+      return Constraint.NEVER;
     }
     if (targetClass.accessFlags.isPublic()) {
-      return InliningConstraint.ALWAYS;
+      return Constraint.ALWAYS;
     }
-    return InliningConstraint.NEVER;
+    return Constraint.NEVER;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 1b18ccc..2e821cf 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Value.DebugInfo;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.utils.CfgPrinter;
 import com.android.tools.r8.utils.InternalOptions;
@@ -797,7 +797,7 @@
   }
 
   // Returns the inlining constraint for this instruction.
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.NEVER;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.NEVER;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
index 2a02218..7b1c007 100644
--- a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
@@ -5,7 +5,7 @@
 
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.List;
 
@@ -47,7 +47,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Move.java b/src/main/java/com/android/tools/r8/ir/code/Move.java
index 6f70c57..91e19f0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Move.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Move.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 public class Move extends Instruction {
 
@@ -81,7 +81,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index 2819c58..142206c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 public class Return extends JumpInstruction {
 
@@ -110,7 +110,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Throw.java b/src/main/java/com/android/tools/r8/ir/code/Throw.java
index e0ba866..9bd6a81 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Throw.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Throw.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 public class Throw extends JumpInstruction {
 
@@ -63,7 +63,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Unop.java b/src/main/java/com/android/tools/r8/ir/code/Unop.java
index ff1744a..174b7b6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Unop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Unop.java
@@ -6,7 +6,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 
 abstract public class Unop extends Instruction {
 
@@ -43,7 +43,7 @@
   }
 
   @Override
-  public InliningConstraint inliningConstraint(AppInfo info, DexType holder) {
-    return InliningConstraint.ALWAYS;
+  public Constraint inliningConstraint(AppInfo info, DexType holder) {
+    return Constraint.ALWAYS;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 8370eb8..3b19b02 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -25,7 +25,7 @@
 import com.android.tools.r8.ir.optimize.CodeRewriter;
 import com.android.tools.r8.ir.optimize.DeadCodeRemover;
 import com.android.tools.r8.ir.optimize.Inliner;
-import com.android.tools.r8.ir.optimize.Inliner.InliningConstraint;
+import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.optimize.MemberValuePropagation;
 import com.android.tools.r8.ir.optimize.Outliner;
 import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
@@ -390,15 +390,15 @@
     boolean matchesMethodFilter = options.methodMatchesFilter(method);
     if (code != null && matchesMethodFilter) {
       assert !method.isProcessed();
-      InliningConstraint state = rewriteCode(method, outlineHandler);
+      Constraint state = rewriteCode(method, outlineHandler);
       method.markProcessed(state);
     } else {
       // Mark abstract methods as processed as well.
-      method.markProcessed(InliningConstraint.NEVER);
+      method.markProcessed(Constraint.NEVER);
     }
   }
 
-  private InliningConstraint rewriteCode(DexEncodedMethod method,
+  private Constraint rewriteCode(DexEncodedMethod method,
       BiConsumer<IRCode, DexEncodedMethod> outlineHandler) {
     if (options.verbose) {
       System.out.println("Processing: " + method.toSourceString());
@@ -409,7 +409,7 @@
     }
     IRCode code = method.buildIR(options);
     if (code == null) {
-      return InliningConstraint.NEVER;
+      return Constraint.NEVER;
     }
     if (Log.ENABLED) {
       Log.debug(getClass(), "Initial (SSA) flow graph for %s:\n%s", method.toSourceString(), code);
@@ -490,7 +490,7 @@
 
     // After all the optimizations have take place, we compute whether method should be inlined.
     if (!options.inlineAccessors || inliner == null) {
-      return InliningConstraint.NEVER;
+      return Constraint.NEVER;
     }
     return inliner.identifySimpleMethods(code, method);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index f677637..f57c022 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -50,23 +50,23 @@
     this.options = options;
   }
 
-  private InliningConstraint instructionAllowedForInlining(
+  private Constraint instructionAllowedForInlining(
       DexEncodedMethod method, Instruction instruction) {
-    InliningConstraint result = instruction.inliningConstraint(appInfo, method.method.holder);
-    if ((result == InliningConstraint.NEVER) && instruction.isDebugInstruction()) {
-      return InliningConstraint.ALWAYS;
+    Constraint result = instruction.inliningConstraint(appInfo, method.method.holder);
+    if ((result == Constraint.NEVER) && instruction.isDebugInstruction()) {
+      return Constraint.ALWAYS;
     }
     return result;
   }
 
-  public InliningConstraint identifySimpleMethods(IRCode code, DexEncodedMethod method) {
+  public Constraint identifySimpleMethods(IRCode code, DexEncodedMethod method) {
     DexCode dex = method.getCode().asDexCode();
     // We have generated code for a method and we want to figure out whether the method is a
     // candidate for inlining. The code is the final IR after optimizations.
     if (dex.instructions.length > INLINING_INSTRUCTION_LIMIT) {
-      return InliningConstraint.NEVER;
+      return Constraint.NEVER;
     }
-    InliningConstraint result = InliningConstraint.ALWAYS;
+    Constraint result = Constraint.ALWAYS;
     ListIterator<BasicBlock> iterator = code.listIterator();
     assert iterator.hasNext();
     BasicBlock block = iterator.next();
@@ -76,9 +76,9 @@
       InstructionListIterator it = block.listIterator();
       while (it.hasNext()) {
         Instruction instruction = it.next();
-        InliningConstraint state = instructionAllowedForInlining(method, instruction);
-        if (state == InliningConstraint.NEVER) {
-          return InliningConstraint.NEVER;
+        Constraint state = instructionAllowedForInlining(method, instruction);
+        if (state == Constraint.NEVER) {
+          return Constraint.NEVER;
         }
         if (state.ordinal() < result.ordinal()) {
           result = state;
@@ -105,7 +105,7 @@
     return methodHolder.isSamePackage(targetHolder);
   }
 
-  public enum InliningConstraint {
+  public enum Constraint {
     // The ordinal values are important so please do not reorder.
     NEVER,    // Never inline this.
     PRIVATE,  // Only inline this into methods with same holder.
@@ -113,23 +113,27 @@
     ALWAYS,   // No restrictions for inlining this.
   }
 
+  public enum Reason {
+    FORCE,         // Inlinee is marked for forced inlining (bridge method or renamed constructor).
+    SINGLE_CALLER, // Inlinee has precisely one caller.
+    DUAL_CALLER,   // Inlinee has precisely two callers.
+    SIMPLE,        // Inlinee has simple code suitable for inlining.
+  }
+
   static public class InlineAction {
 
     public final DexEncodedMethod target;
     public final Invoke invoke;
-    public final boolean forceInline;
+    public final Reason reason;
 
-    public InlineAction(
-        DexEncodedMethod target, Invoke invoke, boolean forceInline) {
+    public InlineAction(DexEncodedMethod target, Invoke invoke, Reason reason) {
       this.target = target;
       this.invoke = invoke;
-      this.forceInline = forceInline;
+      this.reason = reason;
     }
 
-    public InlineAction(DexEncodedMethod target, Invoke invoke) {
-      this.target = target;
-      this.invoke = invoke;
-      this.forceInline = target.getOptimizationInfo().forceInline();
+    public boolean forceInline() {
+      return reason != Reason.SIMPLE;
     }
 
     public IRCode buildIR(ValueNumberGenerator generator, AppInfoWithSubtyping appInfo,
@@ -275,7 +279,7 @@
               // Back up before the invoke instruction.
               iterator.previous();
               instruction_allowance -= numberOfInstructions(inlinee);
-              if (instruction_allowance >= 0 || result.forceInline) {
+              if (instruction_allowance >= 0 || result.forceInline()) {
                 iterator.inlineInvoke(code, inlinee, blockIterator, blocksToRemove, downcast);
               }
               // If we inlined the invoke from a bridge method, it is no longer a bridge method.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 954f11c..7d83150 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.CallGraph;
 import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
+import com.android.tools.r8.ir.optimize.Inliner.Reason;
 import com.android.tools.r8.logging.Log;
 
 /**
@@ -103,6 +104,19 @@
     return candidate;
   }
 
+  private Reason computeInliningReason(DexEncodedMethod target) {
+    if (target.getOptimizationInfo().forceInline()) {
+      return Reason.FORCE;
+    }
+    if (callGraph.hasSingleCallSite(target)) {
+      return Reason.SINGLE_CALLER;
+    }
+    if (isDoubleInliningTarget(target)) {
+      return Reason.DUAL_CALLER;
+    }
+    return Reason.SIMPLE;
+  }
+
   public InlineAction computeForInvokeWithReceiver(InvokeMethodWithReceiver invoke) {
     boolean receiverIsNeverNull = invoke.receiverIsNeverNull();
     if (!receiverIsNeverNull) {
@@ -120,11 +134,9 @@
       return null;
     }
 
-    boolean fromBridgeMethod = target.getOptimizationInfo().forceInline();
-
     if (target == method) {
       // Bridge methods should never have recursive calls.
-      assert !fromBridgeMethod;
+      assert !target.getOptimizationInfo().forceInline();
       return null;
     }
 
@@ -154,11 +166,9 @@
       return null;
     }
 
-    boolean doubleInlineTarget = isDoubleInliningTarget(target);
+    Reason reason = computeInliningReason(target);
     // Determine if this should be inlined no matter how big it is.
-    boolean forceInline =
-        fromBridgeMethod | callGraph.hasSingleCallSite(target) | doubleInlineTarget;
-    if (!target.isInliningCandidate(method, forceInline)) {
+    if (!target.isInliningCandidate(method, reason != Reason.SIMPLE)) {
       // Abort inlining attempt if the single target is not an inlining candidate.
       if (info != null) {
         info.exclude(invoke, "target is not identified for inlining");
@@ -175,7 +185,7 @@
     }
 
     // Attempt to inline a candidate that is only called twice.
-    if (doubleInlineTarget && (doubleInlining(target) == null)) {
+    if ((reason == Reason.DUAL_CALLER) && (doubleInlining(target) == null)) {
       if (info != null) {
         info.exclude(invoke, "target is not ready for double inlining");
       }
@@ -185,7 +195,7 @@
     if (info != null) {
       info.include(invoke.getType(), target);
     }
-    return new InlineAction(target, invoke, forceInline);
+    return new InlineAction(target, invoke, reason);
   }
 
   public InlineAction computeForInvokeVirtual(InvokeVirtual invoke) {
@@ -224,12 +234,9 @@
     if (candidate == null) {
       return null;
     }
-    boolean fromBridgeMethod = candidate.getOptimizationInfo().forceInline();
-    boolean doubleInlineTarget = isDoubleInliningTarget(candidate);
+    Reason reason = computeInliningReason(candidate);
     // Determine if this should be inlined no matter how big it is.
-    boolean forceInline =
-        fromBridgeMethod | callGraph.hasSingleCallSite(candidate) | doubleInlineTarget;
-    if (!candidate.isInliningCandidate(method, forceInline)) {
+    if (!candidate.isInliningCandidate(method, reason != Reason.SIMPLE)) {
       // Abort inlining attempt if the single target is not an inlining candidate.
       if (info != null) {
         info.exclude(invoke, "target is not identified for inlining");
@@ -246,7 +253,7 @@
     }
 
     // Attempt to inline a candidate that is only called twice.
-    if (doubleInlineTarget && (doubleInlining(candidate) == null)) {
+    if ((reason == Reason.DUAL_CALLER) && (doubleInlining(candidate) == null)) {
       if (info != null) {
         info.exclude(invoke, "target is not ready for double inlining");
       }
@@ -256,7 +263,7 @@
     if (info != null) {
       info.include(invoke.getType(), candidate);
     }
-    return new InlineAction(candidate, invoke);
+    return new InlineAction(candidate, invoke, reason);
   }
 
   public InlineAction computeForInvokeSuper(InvokeSuper invoke) {
@@ -270,7 +277,7 @@
     if (info != null) {
       info.include(invoke.getType(), candidate);
     }
-    return new InlineAction(candidate, invoke);
+    return new InlineAction(candidate, invoke, Reason.SIMPLE);
   }
 
   public InlineAction computeForInvokePolymorpic(InvokePolymorphic invoke) {