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