Fix savings estimate in throw block outliner

This also adds a system property that forces outlining when a given outline reaches a given number of users. This can be useful in compiler explorer for unconditionally outlining regardless of the number of users.

Change-Id: I4764cf092e9eaba6915c1d65a2df1b0712671080
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutliner.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutliner.java
index 4aba105..21380b8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutliner.java
@@ -151,6 +151,9 @@
     if (outlineStrategyForTesting != null) {
       return outlineStrategyForTesting.test(outline);
     }
+    if (outline.getNumberOfUsers() >= outlinerOptions.forceUsers) {
+      return true;
+    }
 
     int codeSizeInBytes = outline.getLirCode().estimatedDexCodeSizeUpperBoundInBytes();
     int estimatedCostInBytes;
@@ -188,11 +191,11 @@
     int estimatedSavingsInBytes = 0;
     for (Multiset.Entry<DexMethod> entry : outline.getUsers().entrySet()) {
       // For each call we save the outlined instructions at the cost of an invoke + return.
-      int estimatedSavingsForUser = codeSizeInBytes - 2 * (DexInvokeStatic.SIZE + DexReturn.SIZE);
+      int estimatedSavingsForUser = codeSizeInBytes - (DexInvokeStatic.SIZE + DexReturn.SIZE);
       if (entry.getElement().getReturnType().isWideType()) {
-        estimatedSavingsForUser -= 2 * DexConstWide16.SIZE;
+        estimatedSavingsForUser -= DexConstWide16.SIZE;
       } else if (!entry.getElement().getReturnType().isVoidType()) {
-        estimatedSavingsForUser -= 2 * DexConst4.SIZE;
+        estimatedSavingsForUser -= DexConst4.SIZE;
       }
       estimatedSavingsInBytes += estimatedSavingsForUser * entry.getCount();
       if (estimatedSavingsInBytes > estimatedCostInBytes) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerOptions.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerOptions.java
index 28f17b8..d1b50b6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerOptions.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerOptions.java
@@ -24,6 +24,10 @@
       SystemPropertyUtils.parseSystemPropertyOrDefault(
           "com.android.tools.r8.throwblockoutliner.forcedebug", false);
 
+  public final int forceUsers =
+      SystemPropertyUtils.parseSystemPropertyOrDefault(
+          "com.android.tools.r8.throwblockoutliner.users", Integer.MAX_VALUE);
+
   public Consumer<Collection<ThrowBlockOutline>> outlineConsumerForTesting = null;
   public Predicate<ThrowBlockOutline> outlineStrategyForTesting = null;