Home | History | Annotate | Download | only in desugar
      1 // Copyright 2017 The Bazel Authors. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 package com.google.devtools.build.android.desugar;
     15 
     16 import static com.google.common.base.Preconditions.checkArgument;
     17 import static com.google.common.base.Preconditions.checkNotNull;
     18 import static com.google.common.base.Preconditions.checkState;
     19 
     20 import com.google.auto.value.AutoValue;
     21 import com.google.common.collect.ImmutableList;
     22 import java.util.ArrayList;
     23 import java.util.Optional;
     24 import javax.annotation.Nullable;
     25 import org.objectweb.asm.Handle;
     26 import org.objectweb.asm.Label;
     27 import org.objectweb.asm.MethodVisitor;
     28 import org.objectweb.asm.Opcodes;
     29 import org.objectweb.asm.Type;
     30 
     31 /**
     32  * Perform type inference for byte code (local variables and operand stack) with the help of stack
     33  * map frames.
     34  *
     35  * <p>Note: This class only guarantees the correctness of reference types, but not the primitive
     36  * types, though they might be correct too.
     37  */
     38 public final class BytecodeTypeInference extends MethodVisitor {
     39 
     40   private boolean used = false;
     41   private final ArrayList<InferredType> localVariableSlots;
     42   private final ArrayList<InferredType> operandStack = new ArrayList<>();
     43   private FrameInfo previousFrame;
     44   /** For debugging purpose. */
     45   private final String methodSignature;
     46 
     47   public BytecodeTypeInference(int access, String owner, String name, String methodDescriptor) {
     48     super(Opcodes.ASM6);
     49     localVariableSlots = createInitialLocalVariableTypes(access, owner, name, methodDescriptor);
     50     previousFrame = FrameInfo.create(ImmutableList.copyOf(localVariableSlots), ImmutableList.of());
     51     this.methodSignature = owner + "." + name + methodDescriptor;
     52   }
     53 
     54   public void setDelegateMethodVisitor(MethodVisitor visitor) {
     55     mv = visitor;
     56   }
     57 
     58   @Override
     59   public void visitCode() {
     60     checkState(!used, "Cannot reuse this method visitor.");
     61     used = true;
     62     super.visitCode();
     63   }
     64 
     65   /** Returns the type of a value in the operand. 0 means the top of the stack. */
     66   public InferredType getTypeOfOperandFromTop(int offsetFromTop) {
     67     int index = operandStack.size() - 1 - offsetFromTop;
     68     checkState(
     69         index >= 0,
     70         "Invalid offset %s in the list of size %s. The current method is %s",
     71         offsetFromTop,
     72         operandStack.size(),
     73         methodSignature);
     74     return operandStack.get(index);
     75   }
     76 
     77   public String getOperandStackAsString() {
     78     return operandStack.toString();
     79   }
     80 
     81   public String getLocalsAsString() {
     82     return localVariableSlots.toString();
     83   }
     84 
     85   @Override
     86   public void visitInsn(int opcode) {
     87     switch (opcode) {
     88       case Opcodes.NOP:
     89       case Opcodes.INEG:
     90       case Opcodes.LNEG:
     91       case Opcodes.FNEG:
     92       case Opcodes.DNEG:
     93       case Opcodes.I2B:
     94       case Opcodes.I2C:
     95       case Opcodes.I2S:
     96       case Opcodes.RETURN:
     97         break;
     98       case Opcodes.ACONST_NULL:
     99         push(InferredType.NULL);
    100         break;
    101       case Opcodes.ICONST_M1:
    102       case Opcodes.ICONST_0:
    103       case Opcodes.ICONST_1:
    104       case Opcodes.ICONST_2:
    105       case Opcodes.ICONST_3:
    106       case Opcodes.ICONST_4:
    107       case Opcodes.ICONST_5:
    108         push(InferredType.INT);
    109         break;
    110       case Opcodes.LCONST_0:
    111       case Opcodes.LCONST_1:
    112         push(InferredType.LONG);
    113         push(InferredType.TOP);
    114         break;
    115       case Opcodes.FCONST_0:
    116       case Opcodes.FCONST_1:
    117       case Opcodes.FCONST_2:
    118         push(InferredType.FLOAT);
    119         break;
    120       case Opcodes.DCONST_0:
    121       case Opcodes.DCONST_1:
    122         push(InferredType.DOUBLE);
    123         push(InferredType.TOP);
    124         break;
    125       case Opcodes.IALOAD:
    126       case Opcodes.BALOAD:
    127       case Opcodes.CALOAD:
    128       case Opcodes.SALOAD:
    129         pop(2);
    130         push(InferredType.INT);
    131         break;
    132       case Opcodes.LALOAD:
    133       case Opcodes.D2L:
    134         pop(2);
    135         push(InferredType.LONG);
    136         push(InferredType.TOP);
    137         break;
    138       case Opcodes.DALOAD:
    139       case Opcodes.L2D:
    140         pop(2);
    141         push(InferredType.DOUBLE);
    142         push(InferredType.TOP);
    143         break;
    144       case Opcodes.AALOAD:
    145         InferredType arrayType = pop(2);
    146         InferredType elementType = arrayType.getElementTypeIfArrayOrThrow();
    147         push(elementType);
    148         break;
    149       case Opcodes.IASTORE:
    150       case Opcodes.BASTORE:
    151       case Opcodes.CASTORE:
    152       case Opcodes.SASTORE:
    153       case Opcodes.FASTORE:
    154       case Opcodes.AASTORE:
    155         pop(3);
    156         break;
    157       case Opcodes.LASTORE:
    158       case Opcodes.DASTORE:
    159         pop(4);
    160         break;
    161       case Opcodes.POP:
    162       case Opcodes.IRETURN:
    163       case Opcodes.FRETURN:
    164       case Opcodes.ARETURN:
    165       case Opcodes.ATHROW:
    166       case Opcodes.MONITORENTER:
    167       case Opcodes.MONITOREXIT:
    168         pop();
    169         break;
    170       case Opcodes.POP2:
    171       case Opcodes.LRETURN:
    172       case Opcodes.DRETURN:
    173         pop(2);
    174         break;
    175       case Opcodes.DUP:
    176         push(top());
    177         break;
    178       case Opcodes.DUP_X1:
    179         {
    180           InferredType top = pop();
    181           InferredType next = pop();
    182           push(top);
    183           push(next);
    184           push(top);
    185           break;
    186         }
    187       case Opcodes.DUP_X2:
    188         {
    189           InferredType top = pop();
    190           InferredType next = pop();
    191           InferredType bottom = pop();
    192           push(top);
    193           push(bottom);
    194           push(next);
    195           push(top);
    196           break;
    197         }
    198       case Opcodes.DUP2:
    199         {
    200           InferredType top = pop();
    201           InferredType next = pop();
    202           push(next);
    203           push(top);
    204           push(next);
    205           push(top);
    206           break;
    207         }
    208       case Opcodes.DUP2_X1:
    209         {
    210           InferredType top = pop();
    211           InferredType next = pop();
    212           InferredType bottom = pop();
    213           push(next);
    214           push(top);
    215           push(bottom);
    216           push(next);
    217           push(top);
    218           break;
    219         }
    220       case Opcodes.DUP2_X2:
    221         {
    222           InferredType t1 = pop();
    223           InferredType t2 = pop();
    224           InferredType t3 = pop();
    225           InferredType t4 = pop();
    226           push(t2);
    227           push(t1);
    228           push(t4);
    229           push(t3);
    230           push(t2);
    231           push(t1);
    232           break;
    233         }
    234       case Opcodes.SWAP:
    235         {
    236           InferredType top = pop();
    237           InferredType next = pop();
    238           push(top);
    239           push(next);
    240           break;
    241         }
    242       case Opcodes.IADD:
    243       case Opcodes.ISUB:
    244       case Opcodes.IMUL:
    245       case Opcodes.IDIV:
    246       case Opcodes.IREM:
    247       case Opcodes.ISHL:
    248       case Opcodes.ISHR:
    249       case Opcodes.IUSHR:
    250       case Opcodes.IAND:
    251       case Opcodes.IOR:
    252       case Opcodes.IXOR:
    253       case Opcodes.L2I:
    254       case Opcodes.D2I:
    255       case Opcodes.FCMPL:
    256       case Opcodes.FCMPG:
    257         pop(2);
    258         push(InferredType.INT);
    259         break;
    260 
    261       case Opcodes.LADD:
    262       case Opcodes.LSUB:
    263       case Opcodes.LMUL:
    264       case Opcodes.LDIV:
    265       case Opcodes.LREM:
    266       case Opcodes.LAND:
    267       case Opcodes.LOR:
    268       case Opcodes.LXOR:
    269         pop(4);
    270         push(InferredType.LONG);
    271         push(InferredType.TOP);
    272         break;
    273 
    274       case Opcodes.LSHL:
    275       case Opcodes.LSHR:
    276       case Opcodes.LUSHR:
    277         pop(3);
    278         push(InferredType.LONG);
    279         push(InferredType.TOP);
    280         break;
    281       case Opcodes.I2L:
    282       case Opcodes.F2L:
    283         pop();
    284         push(InferredType.LONG);
    285         push(InferredType.TOP);
    286         break;
    287       case Opcodes.I2F:
    288         pop();
    289         push(InferredType.FLOAT);
    290         break;
    291 
    292       case Opcodes.LCMP:
    293       case Opcodes.DCMPG:
    294       case Opcodes.DCMPL:
    295         pop(4);
    296         push(InferredType.INT);
    297         break;
    298 
    299       case Opcodes.I2D:
    300       case Opcodes.F2D:
    301         pop();
    302         push(InferredType.DOUBLE);
    303         push(InferredType.TOP);
    304         break;
    305       case Opcodes.F2I:
    306       case Opcodes.ARRAYLENGTH:
    307         pop();
    308         push(InferredType.INT);
    309         break;
    310       case Opcodes.FALOAD:
    311       case Opcodes.FADD:
    312       case Opcodes.FSUB:
    313       case Opcodes.FMUL:
    314       case Opcodes.FDIV:
    315       case Opcodes.FREM:
    316       case Opcodes.L2F:
    317       case Opcodes.D2F:
    318         pop(2);
    319         push(InferredType.FLOAT);
    320         break;
    321 
    322       case Opcodes.DADD:
    323       case Opcodes.DSUB:
    324       case Opcodes.DMUL:
    325       case Opcodes.DDIV:
    326       case Opcodes.DREM:
    327         pop(4);
    328         push(InferredType.DOUBLE);
    329         push(InferredType.TOP);
    330         break;
    331       default:
    332         throw new RuntimeException("Unhandled opcode " + opcode);
    333     }
    334     super.visitInsn(opcode);
    335   }
    336 
    337   @Override
    338   public void visitIntInsn(int opcode, int operand) {
    339     switch (opcode) {
    340       case Opcodes.BIPUSH:
    341       case Opcodes.SIPUSH:
    342         push(InferredType.INT);
    343         break;
    344       case Opcodes.NEWARRAY:
    345         pop();
    346         switch (operand) {
    347           case Opcodes.T_BOOLEAN:
    348             pushDescriptor("[Z");
    349             break;
    350           case Opcodes.T_CHAR:
    351             pushDescriptor("[C");
    352             break;
    353           case Opcodes.T_FLOAT:
    354             pushDescriptor("[F");
    355             break;
    356           case Opcodes.T_DOUBLE:
    357             pushDescriptor("[D");
    358             break;
    359           case Opcodes.T_BYTE:
    360             pushDescriptor("[B");
    361             break;
    362           case Opcodes.T_SHORT:
    363             pushDescriptor("[S");
    364             break;
    365           case Opcodes.T_INT:
    366             pushDescriptor("[I");
    367             break;
    368           case Opcodes.T_LONG:
    369             pushDescriptor("[J");
    370             break;
    371           default:
    372             throw new RuntimeException("Unhandled operand value: " + operand);
    373         }
    374         break;
    375       default:
    376         throw new RuntimeException("Unhandled opcode " + opcode);
    377     }
    378     super.visitIntInsn(opcode, operand);
    379   }
    380 
    381   @Override
    382   public void visitVarInsn(int opcode, int var) {
    383     switch (opcode) {
    384       case Opcodes.ILOAD:
    385         push(InferredType.INT);
    386         break;
    387       case Opcodes.LLOAD:
    388         push(InferredType.LONG);
    389         push(InferredType.TOP);
    390         break;
    391       case Opcodes.FLOAD:
    392         push(InferredType.FLOAT);
    393         break;
    394       case Opcodes.DLOAD:
    395         push(InferredType.DOUBLE);
    396         push(InferredType.TOP);
    397         break;
    398       case Opcodes.ALOAD:
    399         push(getLocalVariableType(var));
    400         break;
    401       case Opcodes.ISTORE:
    402       case Opcodes.FSTORE:
    403       case Opcodes.ASTORE:
    404         {
    405           InferredType type = pop();
    406           setLocalVariableTypes(var, type);
    407           break;
    408         }
    409       case Opcodes.LSTORE:
    410       case Opcodes.DSTORE:
    411         {
    412           InferredType type = pop(2);
    413           setLocalVariableTypes(var, type);
    414           setLocalVariableTypes(var + 1, InferredType.TOP);
    415           break;
    416         }
    417       case Opcodes.RET:
    418         throw new RuntimeException("The instruction RET is not supported");
    419       default:
    420         throw new RuntimeException("Unhandled opcode " + opcode);
    421     }
    422     super.visitVarInsn(opcode, var);
    423   }
    424 
    425   @Override
    426   public void visitTypeInsn(int opcode, String type) {
    427     String descriptor = convertToDescriptor(type);
    428     switch (opcode) {
    429       case Opcodes.NEW:
    430         pushDescriptor(descriptor); // This should be UNINITIALIZED(label). Okay for type inference.
    431         break;
    432       case Opcodes.ANEWARRAY:
    433         pop();
    434         pushDescriptor('[' + descriptor);
    435         break;
    436       case Opcodes.CHECKCAST:
    437         pop();
    438         pushDescriptor(descriptor);
    439         break;
    440       case Opcodes.INSTANCEOF:
    441         pop();
    442         push(InferredType.INT);
    443         break;
    444       default:
    445         throw new RuntimeException("Unhandled opcode " + opcode);
    446     }
    447     super.visitTypeInsn(opcode, type);
    448   }
    449 
    450   @Override
    451   public void visitFieldInsn(int opcode, String owner, String name, String desc) {
    452     switch (opcode) {
    453       case Opcodes.GETSTATIC:
    454         pushDescriptor(desc);
    455         break;
    456       case Opcodes.PUTSTATIC:
    457         popDescriptor(desc);
    458         break;
    459       case Opcodes.GETFIELD:
    460         pop();
    461         pushDescriptor(desc);
    462         break;
    463       case Opcodes.PUTFIELD:
    464         popDescriptor(desc);
    465         pop();
    466         break;
    467       default:
    468         throw new RuntimeException(
    469             "Unhandled opcode " + opcode + ", owner=" + owner + ", name=" + name + ", desc" + desc);
    470     }
    471     super.visitFieldInsn(opcode, owner, name, desc);
    472   }
    473 
    474   @Override
    475   public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
    476     if (opcode == Opcodes.INVOKESPECIAL && "<init>".equals(name)) {
    477       int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2);
    478       InferredType receiverType = getTypeOfOperandFromTop(argumentSize - 1);
    479       if (receiverType.isUninitialized()) {
    480         InferredType realType = InferredType.createNonUninitializedType('L' + owner + ';');
    481         replaceUninitializedTypeInStack(receiverType, realType);
    482       }
    483     }
    484     switch (opcode) {
    485       case Opcodes.INVOKESPECIAL:
    486       case Opcodes.INVOKEVIRTUAL:
    487       case Opcodes.INVOKESTATIC:
    488       case Opcodes.INVOKEINTERFACE:
    489         popDescriptor(desc);
    490         if (opcode != Opcodes.INVOKESTATIC) {
    491           pop(); // Pop receiver.
    492         }
    493         pushDescriptor(desc);
    494         break;
    495       default:
    496         throw new RuntimeException(
    497             String.format(
    498                 "Unhandled opcode %s, owner=%s, name=%s, desc=%s, itf=%s",
    499                 opcode, owner, name, desc, itf));
    500     }
    501     super.visitMethodInsn(opcode, owner, name, desc, itf);
    502   }
    503 
    504   @Override
    505   public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
    506     popDescriptor(desc);
    507     pushDescriptor(desc);
    508     super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
    509   }
    510 
    511   @Override
    512   public void visitJumpInsn(int opcode, Label label) {
    513     switch (opcode) {
    514       case Opcodes.IFEQ:
    515       case Opcodes.IFNE:
    516       case Opcodes.IFLT:
    517       case Opcodes.IFGE:
    518       case Opcodes.IFGT:
    519       case Opcodes.IFLE:
    520         pop();
    521         break;
    522       case Opcodes.IF_ICMPEQ:
    523       case Opcodes.IF_ICMPNE:
    524       case Opcodes.IF_ICMPLT:
    525       case Opcodes.IF_ICMPGE:
    526       case Opcodes.IF_ICMPGT:
    527       case Opcodes.IF_ICMPLE:
    528       case Opcodes.IF_ACMPEQ:
    529       case Opcodes.IF_ACMPNE:
    530         pop(2);
    531         break;
    532       case Opcodes.GOTO:
    533         break;
    534       case Opcodes.JSR:
    535         throw new RuntimeException("The JSR instruction is not supported.");
    536       case Opcodes.IFNULL:
    537       case Opcodes.IFNONNULL:
    538         pop(1);
    539         break;
    540       default:
    541         throw new RuntimeException("Unhandled opcode " + opcode);
    542     }
    543     super.visitJumpInsn(opcode, label);
    544   }
    545 
    546   @Override
    547   public void visitLdcInsn(Object cst) {
    548     if (cst instanceof Integer) {
    549       push(InferredType.INT);
    550     } else if (cst instanceof Float) {
    551       push(InferredType.FLOAT);
    552     } else if (cst instanceof Long) {
    553       push(InferredType.LONG);
    554       push(InferredType.TOP);
    555     } else if (cst instanceof Double) {
    556       push(InferredType.DOUBLE);
    557       push(InferredType.TOP);
    558     } else if (cst instanceof String) {
    559       pushDescriptor("Ljava/lang/String;");
    560     } else if (cst instanceof Type) {
    561       pushDescriptor(((Type) cst).getDescriptor());
    562     } else if (cst instanceof Handle) {
    563       pushDescriptor("Ljava/lang/invoke/MethodHandle;");
    564     } else {
    565       throw new RuntimeException("Cannot handle constant " + cst + " for LDC instruction");
    566     }
    567     super.visitLdcInsn(cst);
    568   }
    569 
    570   @Override
    571   public void visitIincInsn(int var, int increment) {
    572     setLocalVariableTypes(var, InferredType.INT);
    573     super.visitIincInsn(var, increment);
    574   }
    575 
    576   @Override
    577   public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
    578     pop();
    579     super.visitTableSwitchInsn(min, max, dflt, labels);
    580   }
    581 
    582   @Override
    583   public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
    584     pop();
    585     super.visitLookupSwitchInsn(dflt, keys, labels);
    586   }
    587 
    588   @Override
    589   public void visitMultiANewArrayInsn(String desc, int dims) {
    590     pop(dims);
    591     pushDescriptor(desc);
    592     super.visitMultiANewArrayInsn(desc, dims);
    593   }
    594 
    595   @Override
    596   public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
    597     switch (type) {
    598       case Opcodes.F_NEW:
    599         // Expanded form.
    600         previousFrame =
    601             FrameInfo.create(
    602                 convertTypesInStackMapFrame(nLocal, local),
    603                 convertTypesInStackMapFrame(nStack, stack));
    604         break;
    605       case Opcodes.F_SAME:
    606         // This frame type indicates that the frame has exactly the same local variables as the
    607         // previous frame and that the operand stack is empty.
    608         previousFrame = FrameInfo.create(previousFrame.locals(), ImmutableList.of());
    609         break;
    610       case Opcodes.F_SAME1:
    611         // This frame type indicates that the frame has exactly the same local variables as the
    612         // previous frame and that the operand stack has one entry.
    613         previousFrame =
    614             FrameInfo.create(previousFrame.locals(), convertTypesInStackMapFrame(nStack, stack));
    615         break;
    616       case Opcodes.F_APPEND:
    617         // This frame type indicates that the frame has the same locals as the previous frame except
    618         // that k additional locals are defined, and that the operand stack is empty.
    619         previousFrame =
    620             FrameInfo.create(
    621                 appendArrayToList(previousFrame.locals(), nLocal, local), ImmutableList.of());
    622         break;
    623       case Opcodes.F_CHOP:
    624         // This frame type indicates that the frame has the same local variables as the previous
    625         // frame except that the last k local variables are absent, and that the operand stack is
    626         // empty.
    627         previousFrame =
    628             FrameInfo.create(
    629                 removeBackFromList(previousFrame.locals(), nLocal), ImmutableList.of());
    630         break;
    631       case Opcodes.F_FULL:
    632         previousFrame =
    633             FrameInfo.create(
    634                 convertTypesInStackMapFrame(nLocal, local),
    635                 convertTypesInStackMapFrame(nStack, stack));
    636         break;
    637       default:
    638         // continue below
    639     }
    640     // Update types for operand stack and local variables.
    641     operandStack.clear();
    642     operandStack.addAll(previousFrame.stack());
    643     localVariableSlots.clear();
    644     localVariableSlots.addAll(previousFrame.locals());
    645     super.visitFrame(type, nLocal, local, nStack, stack);
    646   }
    647 
    648   private static String convertToDescriptor(String type) {
    649     char firstChar = type.charAt(0);
    650     switch (firstChar) {
    651       case 'Z':
    652       case 'B':
    653       case 'C':
    654       case 'S':
    655       case 'I':
    656       case 'J':
    657       case 'D':
    658       case 'F':
    659       case '[':
    660         return type;
    661       default:
    662         return 'L' + type + ';';
    663     }
    664   }
    665 
    666   private void push(InferredType type) {
    667     operandStack.add(type);
    668   }
    669 
    670   private void replaceUninitializedTypeInStack(InferredType oldType, InferredType newType) {
    671     checkArgument(oldType.isUninitialized(), "The old type is NOT uninitialized. %s", oldType);
    672     for (int i = 0, size = operandStack.size(); i < size; ++i) {
    673       InferredType type = operandStack.get(i);
    674       if (type.equals(oldType)) {
    675         operandStack.set(i, newType);
    676       }
    677     }
    678   }
    679 
    680   private final void pushDescriptor(String desc) {
    681     int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
    682     switch (desc.charAt(index)) {
    683       case 'V':
    684         return;
    685       case 'Z':
    686       case 'C':
    687       case 'B':
    688       case 'S':
    689       case 'I':
    690         push(InferredType.INT);
    691         break;
    692       case 'F':
    693         push(InferredType.FLOAT);
    694         break;
    695       case 'D':
    696         push(InferredType.DOUBLE);
    697         push(InferredType.TOP);
    698         break;
    699       case 'J':
    700         push(InferredType.LONG);
    701         push(InferredType.TOP);
    702         break;
    703       case 'L':
    704       case '[':
    705         push(InferredType.createNonUninitializedType(desc.substring(index)));
    706         break;
    707       default:
    708         throw new RuntimeException("Unhandled type: " + desc);
    709     }
    710   }
    711 
    712   private final InferredType pop() {
    713     return pop(1);
    714   }
    715 
    716   private final void popDescriptor(String desc) {
    717     char c = desc.charAt(0);
    718     switch (c) {
    719       case '(':
    720         int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2) - 1;
    721         if (argumentSize > 0) {
    722           pop(argumentSize);
    723         }
    724         break;
    725       case 'J':
    726       case 'D':
    727         pop(2);
    728         break;
    729       default:
    730         pop(1);
    731         break;
    732     }
    733   }
    734 
    735   private final InferredType getLocalVariableType(int index) {
    736     checkState(
    737         index < localVariableSlots.size(),
    738         "Cannot find type for var %s in method %s",
    739         index,
    740         methodSignature);
    741     return localVariableSlots.get(index);
    742   }
    743 
    744   private final void setLocalVariableTypes(int index, InferredType type) {
    745     while (localVariableSlots.size() <= index) {
    746       localVariableSlots.add(InferredType.TOP);
    747     }
    748     localVariableSlots.set(index, type);
    749   }
    750 
    751   private final InferredType top() {
    752     return operandStack.get(operandStack.size() - 1);
    753   }
    754 
    755   /** Pop elements from the end of the operand stack, and return the last popped element. */
    756   private final InferredType pop(int count) {
    757     checkArgument(
    758         count >= 1, "The count should be at least one: %s (In %s)", count, methodSignature);
    759     checkState(
    760         operandStack.size() >= count,
    761         "There are no enough elements in the stack. count=%s, stack=%s (In %s)",
    762         count,
    763         operandStack,
    764         methodSignature);
    765     int expectedLastIndex = operandStack.size() - count - 1;
    766     InferredType lastPopped = null;
    767     for (int i = operandStack.size() - 1; i > expectedLastIndex; --i) {
    768       lastPopped = operandStack.remove(i);
    769     }
    770     return lastPopped;
    771   }
    772 
    773   /**
    774    * Create the types of local variables at the very beginning of the method with the information of
    775    * the declaring class and the method descriptor.
    776    */
    777   private static ArrayList<InferredType> createInitialLocalVariableTypes(
    778       int access, String ownerClass, String methodName, String methodDescriptor) {
    779     ArrayList<InferredType> types = new ArrayList<>();
    780 
    781     if (!BitFlags.isSet(access, Opcodes.ACC_STATIC)) {
    782       // Instance method, and this is the receiver
    783       types.add(InferredType.createNonUninitializedType(convertToDescriptor(ownerClass)));
    784     }
    785     Type[] argumentTypes = Type.getArgumentTypes(methodDescriptor);
    786     for (Type argumentType : argumentTypes) {
    787       switch (argumentType.getSort()) {
    788         case Type.BOOLEAN:
    789         case Type.BYTE:
    790         case Type.CHAR:
    791         case Type.SHORT:
    792         case Type.INT:
    793           types.add(InferredType.INT);
    794           break;
    795         case Type.FLOAT:
    796           types.add(InferredType.FLOAT);
    797           break;
    798         case Type.LONG:
    799           types.add(InferredType.LONG);
    800           types.add(InferredType.TOP);
    801           break;
    802         case Type.DOUBLE:
    803           types.add(InferredType.DOUBLE);
    804           types.add(InferredType.TOP);
    805           break;
    806         case Type.ARRAY:
    807         case Type.OBJECT:
    808           types.add(InferredType.createNonUninitializedType(argumentType.getDescriptor()));
    809           break;
    810         default:
    811           throw new RuntimeException(
    812               "Unhandled argument type: "
    813                   + argumentType
    814                   + " in "
    815                   + ownerClass
    816                   + "."
    817                   + methodName
    818                   + methodDescriptor);
    819       }
    820     }
    821     return types;
    822   }
    823 
    824   private static ImmutableList<InferredType> removeBackFromList(
    825       ImmutableList<InferredType> list, int countToRemove) {
    826     int origSize = list.size();
    827     int index = origSize - 1;
    828 
    829     while (index >= 0 && countToRemove > 0) {
    830       InferredType type = list.get(index);
    831       if (type.equals(InferredType.TOP) && index > 0 && list.get(index - 1).isCategory2()) {
    832         --index; // A category 2 takes two slots.
    833       }
    834       --index; // Eat this local variable.
    835       --countToRemove;
    836     }
    837     checkState(
    838         countToRemove == 0,
    839         "countToRemove is %s but not 0. index=%s, list=%s",
    840         countToRemove,
    841         index,
    842         list);
    843     return list.subList(0, index + 1);
    844   }
    845 
    846   private ImmutableList<InferredType> appendArrayToList(
    847       ImmutableList<InferredType> list, int size, Object[] array) {
    848     ImmutableList.Builder<InferredType> builder = ImmutableList.builder();
    849     builder.addAll(list);
    850     for (int i = 0; i < size; ++i) {
    851       InferredType type = convertTypeInStackMapFrame(array[i]);
    852       builder.add(type);
    853       if (type.isCategory2()) {
    854         builder.add(InferredType.TOP);
    855       }
    856     }
    857     return builder.build();
    858   }
    859 
    860   /** Convert the type in stack map frame to inference type. */
    861   private InferredType convertTypeInStackMapFrame(Object typeInStackMapFrame) {
    862     if (typeInStackMapFrame == Opcodes.TOP) {
    863       return InferredType.TOP;
    864     } else if (typeInStackMapFrame == Opcodes.INTEGER) {
    865       return InferredType.INT;
    866     } else if (typeInStackMapFrame == Opcodes.FLOAT) {
    867       return InferredType.FLOAT;
    868     } else if (typeInStackMapFrame == Opcodes.DOUBLE) {
    869       return InferredType.DOUBLE;
    870     } else if (typeInStackMapFrame == Opcodes.LONG) {
    871       return InferredType.LONG;
    872     } else if (typeInStackMapFrame == Opcodes.NULL) {
    873       return InferredType.NULL;
    874     } else if (typeInStackMapFrame == Opcodes.UNINITIALIZED_THIS) {
    875       return InferredType.UNINITIALIZED_THIS;
    876     } else if (typeInStackMapFrame instanceof String) {
    877       String referenceTypeName = (String) typeInStackMapFrame;
    878       if (referenceTypeName.charAt(0) == '[') {
    879         return InferredType.createNonUninitializedType(referenceTypeName);
    880       } else {
    881         return InferredType.createNonUninitializedType('L' + referenceTypeName + ';');
    882       }
    883     } else if (typeInStackMapFrame instanceof Label) {
    884       Label label = (Label) typeInStackMapFrame;
    885       return InferredType.createUninitializedType(label);
    886     } else {
    887       throw new RuntimeException(
    888           "Cannot reach here. Unhandled element: value="
    889               + typeInStackMapFrame
    890               + ", class="
    891               + typeInStackMapFrame.getClass()
    892               + ". The current method being desugared is "
    893               + methodSignature);
    894     }
    895   }
    896 
    897   private ImmutableList<InferredType> convertTypesInStackMapFrame(int size, Object[] array) {
    898     ImmutableList.Builder<InferredType> builder = ImmutableList.builder();
    899     for (int i = 0; i < size; ++i) {
    900       InferredType type = convertTypeInStackMapFrame(array[i]);
    901       builder.add(type);
    902       if (type.isCategory2()) {
    903         builder.add(InferredType.TOP);
    904       }
    905     }
    906     return builder.build();
    907   }
    908 
    909   /** A value class to represent a frame. */
    910   @AutoValue
    911   abstract static class FrameInfo {
    912 
    913     static FrameInfo create(ImmutableList<InferredType> locals, ImmutableList<InferredType> stack) {
    914       return new AutoValue_BytecodeTypeInference_FrameInfo(locals, stack);
    915     }
    916 
    917     abstract ImmutableList<InferredType> locals();
    918 
    919     abstract ImmutableList<InferredType> stack();
    920   }
    921 
    922   /** This is the type used for type inference. */
    923   @AutoValue
    924   public abstract static class InferredType {
    925 
    926     public static final String UNINITIALIZED_PREFIX = "UNINIT@";
    927 
    928     public static final InferredType BOOLEAN =
    929         new AutoValue_BytecodeTypeInference_InferredType("Z", /*uninitializationLabel=*/ null);
    930     public static final InferredType BYTE =
    931         new AutoValue_BytecodeTypeInference_InferredType("B", /*uninitializationLabel=*/ null);
    932     public static final InferredType INT =
    933         new AutoValue_BytecodeTypeInference_InferredType("I", /*uninitializationLabel=*/ null);
    934     public static final InferredType FLOAT =
    935         new AutoValue_BytecodeTypeInference_InferredType("F", /*uninitializationLabel=*/ null);
    936     public static final InferredType LONG =
    937         new AutoValue_BytecodeTypeInference_InferredType("J", /*uninitializationLabel=*/ null);
    938     public static final InferredType DOUBLE =
    939         new AutoValue_BytecodeTypeInference_InferredType("D", /*uninitializationLabel=*/ null);
    940     /** Not a real value. */
    941     public static final InferredType TOP =
    942         new AutoValue_BytecodeTypeInference_InferredType("TOP", /*uninitializationLabel=*/ null);
    943     /** The value NULL */
    944     public static final InferredType NULL =
    945         new AutoValue_BytecodeTypeInference_InferredType("NULL", /*uninitializationLabel=*/ null);
    946 
    947     public static final InferredType UNINITIALIZED_THIS =
    948         new AutoValue_BytecodeTypeInference_InferredType(
    949             "UNINITIALIZED_THIS", /*uninitializationLabel=*/ null);
    950 
    951     /**
    952      * Create a type for a value. This method is not intended to be called outside of this class.
    953      */
    954     private static InferredType create(String descriptor, @Nullable Label uninitializationLabel) {
    955       if (UNINITIALIZED_PREFIX.equals(descriptor)) {
    956         return new AutoValue_BytecodeTypeInference_InferredType(
    957             UNINITIALIZED_PREFIX, checkNotNull(uninitializationLabel));
    958       }
    959       checkArgument(
    960           uninitializationLabel == null,
    961           "The uninitializationLabel should be null for non-uninitialized value. %s",
    962           descriptor);
    963       char firstChar = descriptor.charAt(0);
    964       if (firstChar == 'L' || firstChar == '[') {
    965         // Reference, array.
    966         return new AutoValue_BytecodeTypeInference_InferredType(
    967             descriptor, /*uninitializationLabel=*/ null);
    968       }
    969       switch (descriptor) {
    970         case "Z":
    971           return BOOLEAN;
    972         case "B":
    973           return BYTE;
    974         case "I":
    975           return INT;
    976         case "F":
    977           return FLOAT;
    978         case "J":
    979           return LONG;
    980         case "D":
    981           return DOUBLE;
    982         case "TOP":
    983           return TOP;
    984         case "NULL":
    985           return NULL;
    986         case "UNINITIALIZED_THIS":
    987           return UNINITIALIZED_THIS;
    988         default:
    989           throw new RuntimeException("Invalid descriptor: " + descriptor);
    990       }
    991     }
    992 
    993     /** Creates all types except UNINITIALIZED. This method can also create UNINTIALIZED_THIS. */
    994     static InferredType createNonUninitializedType(String descriptor) {
    995       return create(descriptor, /*uninitializationLabel=*/ null);
    996     }
    997 
    998     /** Create a type for an UNINITIALIZED value. The uninitializationLabel is generated by ASM. */
    999     static InferredType createUninitializedType(Label uninitializationLabel) {
   1000       return create(UNINITIALIZED_PREFIX, uninitializationLabel);
   1001     }
   1002 
   1003     abstract String descriptor();
   1004     /**
   1005      * The label may be null. This field is meaningful if the current type is "UNINITIALIZED". For
   1006      * other types, this field is null.
   1007      */
   1008     @Nullable
   1009     abstract Label uninitializationLabel();
   1010 
   1011     @Override
   1012     public String toString() {
   1013       return descriptor();
   1014     }
   1015 
   1016     /** Is a category 2 value? */
   1017     public boolean isCategory2() {
   1018       String descriptor = descriptor();
   1019       return descriptor.equals("J") || descriptor.equals("D");
   1020     }
   1021 
   1022     /** If the type is an array, return the element type. Otherwise, throw an exception. */
   1023     public InferredType getElementTypeIfArrayOrThrow() {
   1024       String descriptor = descriptor();
   1025       checkState(descriptor.charAt(0) == '[', "This type %s is not an array.", this);
   1026       return createNonUninitializedType(descriptor.substring(1));
   1027     }
   1028 
   1029     /** Is an uninitialized value? */
   1030     public boolean isUninitialized() {
   1031       return descriptor().startsWith(UNINITIALIZED_PREFIX);
   1032     }
   1033 
   1034     /** Is a null value? */
   1035     public boolean isNull() {
   1036       return NULL.equals(this);
   1037     }
   1038 
   1039     /**
   1040      * If this type is a reference type, then return the internal name. Otherwise, returns empty.
   1041      */
   1042     public Optional<String> getInternalName() {
   1043       String descriptor = descriptor();
   1044       int length = descriptor.length();
   1045       if (length > 0 && descriptor.charAt(0) == 'L' && descriptor.charAt(length - 1) == ';') {
   1046         return Optional.of(descriptor.substring(1, length - 1));
   1047       } else {
   1048         return Optional.empty();
   1049       }
   1050     }
   1051   }
   1052 }
   1053