View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit.internal.util;
6   
7   import static mockit.asm.jvmConstants.Opcodes.ASTORE;
8   import static mockit.asm.jvmConstants.Opcodes.CHECKCAST;
9   import static mockit.asm.jvmConstants.Opcodes.INVOKESTATIC;
10  import static mockit.asm.jvmConstants.Opcodes.INVOKEVIRTUAL;
11  import static mockit.asm.jvmConstants.Opcodes.POP;
12  
13  import edu.umd.cs.findbugs.annotations.NonNull;
14  
15  import mockit.asm.methods.MethodVisitor;
16  import mockit.asm.types.JavaType;
17  import mockit.asm.types.PrimitiveType;
18  import mockit.asm.types.ReferenceType;
19  
20  import org.checkerframework.checker.index.qual.NonNegative;
21  
22  public final class TypeConversionBytecode {
23      private TypeConversionBytecode() {
24      }
25  
26      public static void generateCastToObject(@NonNull MethodVisitor mv, @NonNull JavaType type) {
27          if (type instanceof PrimitiveType) {
28              String wrapperTypeDesc = ((PrimitiveType) type).getWrapperTypeDesc();
29              String desc = '(' + type.getDescriptor() + ")L" + wrapperTypeDesc + ';';
30  
31              mv.visitMethodInsn(INVOKESTATIC, wrapperTypeDesc, "valueOf", desc, false);
32          }
33      }
34  
35      public static void generateCastFromObject(@NonNull MethodVisitor mv, @NonNull JavaType toType) {
36          if (toType instanceof PrimitiveType) {
37              PrimitiveType primitiveType = (PrimitiveType) toType;
38  
39              if (primitiveType.getType() == void.class) {
40                  mv.visitInsn(POP);
41              } else {
42                  generateTypeCheck(mv, primitiveType);
43                  generateUnboxing(mv, primitiveType);
44              }
45          } else {
46              generateTypeCheck(mv, toType);
47          }
48      }
49  
50      private static void generateTypeCheck(@NonNull MethodVisitor mv, @NonNull JavaType toType) {
51          String typeDesc;
52  
53          if (toType instanceof ReferenceType) {
54              typeDesc = ((ReferenceType) toType).getInternalName();
55          } else {
56              typeDesc = ((PrimitiveType) toType).getWrapperTypeDesc();
57          }
58  
59          mv.visitTypeInsn(CHECKCAST, typeDesc);
60      }
61  
62      private static void generateUnboxing(@NonNull MethodVisitor mv, @NonNull PrimitiveType primitiveType) {
63          String owner = primitiveType.getWrapperTypeDesc();
64          String methodName = primitiveType.getClassName() + "Value";
65          String methodDesc = "()" + primitiveType.getTypeCode();
66  
67          mv.visitMethodInsn(INVOKEVIRTUAL, owner, methodName, methodDesc, false);
68      }
69  
70      public static void generateCastOrUnboxing(@NonNull MethodVisitor mv, @NonNull JavaType parameterType,
71              @NonNegative int opcode) {
72          if (opcode == ASTORE) {
73              generateTypeCheck(mv, parameterType);
74              return;
75          }
76  
77          String typeDesc = ((ReferenceType) parameterType).getInternalName();
78          mv.visitTypeInsn(CHECKCAST, typeDesc);
79  
80          PrimitiveType primitiveType = PrimitiveType.getCorrespondingPrimitiveTypeIfWrapperType(typeDesc);
81          assert primitiveType != null;
82  
83          generateUnboxing(mv, primitiveType);
84      }
85  
86      public static boolean isPrimitiveWrapper(@NonNull String typeDesc) {
87          return PrimitiveType.getCorrespondingPrimitiveTypeIfWrapperType(typeDesc) != null;
88      }
89  
90      public static boolean isBoxing(@NonNull String owner, @NonNull String name, @NonNull String desc) {
91          return desc.charAt(2) == ')' && "valueOf".equals(name) && isPrimitiveWrapper(owner);
92      }
93  
94      public static boolean isUnboxing(@NonNegative int opcode, @NonNull String owner, @NonNull String desc) {
95          return opcode == INVOKEVIRTUAL && desc.charAt(1) == ')' && isPrimitiveWrapper(owner);
96      }
97  }