1
2
3
4
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 }