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