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