Calculate conservative bytecode size of CF instructions

Bug: b/225839019
Change-Id: I150e12cf6cc4b8184485fd0630f258fe59e7f0bf
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index efad6db..67e44d4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -162,6 +162,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public boolean canThrow() {
     return (type != NumericType.FLOAT && type != NumericType.DOUBLE)
         && (opcode == Opcode.Div || opcode == Opcode.Rem);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 0af6a11..35a03f2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -40,6 +40,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public int getCompareToId() {
     return Opcodes.ARRAYLENGTH;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index 44f0e60..dc6a732 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -89,6 +89,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 68d6b2d..39db93e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -87,6 +87,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 6098e98..edd6603 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -92,6 +92,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index c997da1..5b3c937 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -112,6 +112,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
     int right = state.pop().register;
     int left = state.pop().register;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 0e878ae..abc6070 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -94,6 +94,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // ldc or ldc_w
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index 4efa8ae..3416ff7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -189,6 +189,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // ldc or ldc_w
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index 5f5837a..48db7ef 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -67,6 +67,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // ldc or ldc_w
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 3ef0e8d..855690f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -65,6 +65,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // ldc or ldc_w
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index 4d7dbb7..d58b161 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -40,6 +40,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public int getCompareToId() {
     return Opcodes.ACONST_NULL;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index abd71c5..b1d9c5b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -146,6 +146,64 @@
     }
   }
 
+  @Override
+  public int bytecodeSizeUpperBound() {
+    switch (type) {
+      case INT:
+        {
+          int value = getIntValue();
+          if (-1 <= value && value <= 5) {
+            // iconst_0 .. iconst_5
+            return 1;
+          } else if (Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE) {
+            // bipush byte
+            return 2;
+          } else if (Short.MIN_VALUE <= value && value <= Short.MAX_VALUE) {
+            // sipush byte1 byte2
+            return 3;
+          } else {
+            // ldc or ldc_w
+            return 3;
+          }
+        }
+      case LONG:
+        {
+          long value = getLongValue();
+          if (value == 0 || value == 1) {
+            // lconst_0 .. lconst_1
+            return 1;
+          } else {
+            // ldc or ldc_w
+            return 3;
+          }
+        }
+      case FLOAT:
+        {
+          float value = getFloatValue();
+          if (value == 0 || value == 1 || value == 2) {
+            // fconst_0 .. fconst_2 followed by fneg if negative
+            return isNegativeZeroFloat(value) ? 2 : 1;
+          } else {
+            // ldc or ldc_w
+            return 3;
+          }
+        }
+      case DOUBLE:
+        {
+          double value = getDoubleValue();
+          if (value == 0 || value == 1) {
+            // dconst_0 .. dconst_2 followed by dneg if negative
+            return isNegativeZeroDouble(value) ? 2 : 1;
+          } else {
+            // ldc2_w
+            return 3;
+          }
+        }
+      default:
+        throw new Unreachable("Non supported type in cf backend: " + type);
+    }
+  }
+
   public static boolean isNegativeZeroDouble(double value) {
     return Double.doubleToLongBits(value) == Double.doubleToLongBits(-0.0);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 1b46a48..f03e9c7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -74,6 +74,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // ldc or ldc_w
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 0a6887a..cdc4235 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -82,6 +82,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // ldc or ldc_w
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 99c9151..29dc73f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -122,6 +122,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index 31bc71c..7f7f08b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -404,6 +404,11 @@
     visitor.visitFrame(F_NEW, localsCount, localsTypes, stackCount, stackTypes);
   }
 
+  @Override
+  public int bytecodeSizeUpperBound() {
+    return 0;
+  }
+
   private int computeStackCount() {
     return stack.size();
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index eb82f47..fa3a8a5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -76,6 +76,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index 9db12ec..833ac44 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -104,6 +104,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public boolean isConditionalJump() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index 2340a89..c8129a6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -105,6 +105,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public boolean isConditionalJump() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 735dde8..1b5763c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -64,6 +64,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // iinc or wide iinc
+    return var < 256 && increment < 256 ? 3 : 6;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index 1092bfe..c307d45 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -82,6 +82,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index 0f93c4d..0469499 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -91,6 +91,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index a1b7023..40b9737 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.code.CfOrDexInstruction;
 import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
@@ -66,6 +67,10 @@
   public abstract int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper);
 
+  public int bytecodeSizeUpperBound() {
+    throw new Unreachable("Instruction must specify size");
+  }
+
   public final int acceptCompareTo(
       CfInstruction o, CompareToVisitor visitor, CfCompareHelper helper) {
     int diff = visitor.visitInt(getCompareToId(), o.getCompareToId());
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 9fb383a..8397bc6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -112,6 +112,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return opcode == Opcodes.INVOKEINTERFACE ? 5 : 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index 2082290..a02060b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -92,6 +92,11 @@
         bsmArgs);
   }
 
+  @Override
+  public int bytecodeSizeUpperBound() {
+    return 5;
+  }
+
   private Object decodeBootstrapArgument(DexValue value, NamingLens lens) {
     switch (value.getValueKind()) {
       case DOUBLE:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index 51829ec..bc866cb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -62,6 +62,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    throw error();
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 1f611b1..9e3b1ee 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -74,6 +74,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 0;
+  }
+
+  @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
     // Intentionally left empty.
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 4f9a4db..99a32da 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -88,6 +88,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // xload_0 .. xload_3, xload or wide xload, where x is a, i, f, l or d
+    return var <= 3 ? 1 : ((var < 256) ? 2 : 4);
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 71e31d8..2407b10 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -137,6 +137,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
     int right = state.pop().register;
     int left = state.pop().register;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index 557d380..11df4ee 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -62,6 +62,11 @@
     visitor.visitInsn(getAsmOpcode());
   }
 
+  @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
   private int getAsmOpcode() {
     return type == Type.ENTER ? Opcodes.MONITORENTER : Opcodes.MONITOREXIT;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 33fed6e..509e0cf 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -93,6 +93,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 4;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index a2621a8..da12fc5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -64,6 +64,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index 95deb22..b4c070a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -82,6 +82,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 3;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 50f82d0..5149789 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -128,6 +128,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 2;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index 0d283d4..0c75328 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -85,6 +85,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    throw new Unreachable();
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index 3518f2a..f77241e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -50,6 +50,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index 13c737d..b8fe9c1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -74,6 +74,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index e7bf24a..6f82c07 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -63,6 +63,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 0;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index ec9b7df..f8fad92 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -54,6 +54,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    throw new Unreachable();
+  }
+
+  @Override
   public CfRecordFieldValues asRecordFieldValues() {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index 68038a4..d06db87 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -67,6 +67,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public boolean isJump() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 9072b97..d492b04 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -55,6 +55,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index 289846f..366033d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -108,6 +108,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index b096223..616ed84 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -91,6 +91,12 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    // xstore_0 .. xstore_3, xstore or wide xstore, where x is a, i, f, l or d
+    return var <= 3 ? 1 : ((var < 256) ? 2 : 4);
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 6321c35..a86bcd1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
@@ -121,6 +122,20 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    switch (kind) {
+      case LOOKUP:
+        return 8 + keys.length * 8;
+      case TABLE:
+        int min = keys[0];
+        int max = min + targets.size() - 1;
+        return 16 + (max - min + 1) * 4;
+      default:
+        throw new Unreachable();
+    }
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index fc36a53..6e5eb78 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -66,6 +66,11 @@
   }
 
   @Override
+  public int bytecodeSizeUpperBound() {
+    return 1;
+  }
+
+  @Override
   public void print(CfPrinter printer) {
     printer.print(this);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 5f31229..910d5f5 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -311,6 +311,16 @@
     return estimatedSizeForInlining() * Base5Format.SIZE;
   }
 
+  public int bytecodeSizeUpperBound() {
+    int result = 0;
+    for (CfInstruction instruction : instructions) {
+      int delta = instruction.bytecodeSizeUpperBound();
+      assert delta > 0 || !instruction.emitsIR();
+      result += delta;
+    }
+    return result;
+  }
+
   private int countNonStackOperations(int threshold) {
     int result = 0;
     for (CfInstruction instruction : instructions) {
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 1332bf7..11f0a2c 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -594,6 +594,7 @@
       MethodVisitor visitor) {
     Code code = method.getDefinition().getCode();
     assert code.isCfWritableCode();
+    assert code.estimatedDexCodeSizeUpperBoundInBytes() > 0;
     code.asCfWritableCode()
         .writeCf(method, classFileVersion, appView, namingLens, rewriter, visitor);
   }