1
2
3
4
5
6 package mockit.asm.types;
7
8 import static mockit.asm.jvmConstants.Opcodes.DCONST_0;
9 import static mockit.asm.jvmConstants.Opcodes.DLOAD;
10 import static mockit.asm.jvmConstants.Opcodes.FCONST_0;
11 import static mockit.asm.jvmConstants.Opcodes.FLOAD;
12 import static mockit.asm.jvmConstants.Opcodes.IALOAD;
13 import static mockit.asm.jvmConstants.Opcodes.IASTORE;
14 import static mockit.asm.jvmConstants.Opcodes.ICONST_0;
15 import static mockit.asm.jvmConstants.Opcodes.ILOAD;
16 import static mockit.asm.jvmConstants.Opcodes.LCONST_0;
17 import static mockit.asm.jvmConstants.Opcodes.LLOAD;
18
19 import edu.umd.cs.findbugs.annotations.NonNull;
20 import edu.umd.cs.findbugs.annotations.Nullable;
21
22 import mockit.asm.jvmConstants.ArrayElementType;
23
24 import org.checkerframework.checker.index.qual.NonNegative;
25
26 public final class PrimitiveType extends JavaType {
27 private static final Class<?>[] TYPES = { void.class, boolean.class, char.class, byte.class, short.class, int.class,
28 float.class, long.class, double.class };
29 private static final String[] WRAPPER_TYPE_DESCS = { "java/lang/Void", "java/lang/Boolean", "java/lang/Character",
30 "java/lang/Byte", "java/lang/Short", "java/lang/Integer", "java/lang/Float", "java/lang/Long",
31 "java/lang/Double" };
32 private static final char[] TYPE_CODES = { 'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D' };
33 private static final String TYPE_CODES_STR = "VZCBSIFJD";
34 private static final int[] ARRAY_ELEMENT_TYPES = { 0, ArrayElementType.BOOLEAN, ArrayElementType.CHAR,
35 ArrayElementType.BYTE, ArrayElementType.SHORT, ArrayElementType.INT, ArrayElementType.FLOAT,
36 ArrayElementType.LONG, ArrayElementType.DOUBLE };
37 private static final PrimitiveType VOID = new PrimitiveType(0, 0);
38 private static final PrimitiveType BOOLEAN = new PrimitiveType(1, 5);
39 private static final PrimitiveType CHAR = new PrimitiveType(2, 6);
40 private static final PrimitiveType BYTE = new PrimitiveType(3, 5);
41 private static final PrimitiveType SHORT = new PrimitiveType(4, 7);
42 private static final PrimitiveType INT = new PrimitiveType(5, 0);
43 private static final PrimitiveType FLOAT = new PrimitiveType(6, 2);
44 private static final PrimitiveType LONG = new PrimitiveType(7, 1);
45 private static final PrimitiveType DOUBLE = new PrimitiveType(8, 3);
46 private static final PrimitiveType[] JAVA_TYPES = { VOID, BOOLEAN, CHAR, BYTE, SHORT, INT, FLOAT, LONG, DOUBLE };
47
48 @NonNegative
49 private final int index;
50 @NonNegative
51 private final int loadOrStoreOffset;
52 @NonNegative
53 private final int otherOffset;
54 @NonNegative
55 private final int size;
56 @NonNegative
57 private final int loadOpcode;
58 @NonNegative
59 private final int constOpcode;
60 @NonNull
61 private final String wrapperTypeDesc;
62
63 private PrimitiveType(@NonNegative int index, @NonNegative int otherOffset) {
64 super(1);
65 this.index = index;
66 this.otherOffset = otherOffset;
67 wrapperTypeDesc = WRAPPER_TYPE_DESCS[index];
68
69 Class<?> type = TYPES[index];
70
71 if (type == void.class) {
72 loadOrStoreOffset = 5;
73 size = 0;
74 loadOpcode = 0;
75 constOpcode = 0;
76 } else if (type == float.class) {
77 loadOrStoreOffset = 2;
78 size = 1;
79 loadOpcode = FLOAD;
80 constOpcode = FCONST_0;
81 } else if (type == long.class) {
82 loadOrStoreOffset = 1;
83 size = 2;
84 loadOpcode = LLOAD;
85 constOpcode = LCONST_0;
86 } else if (type == double.class) {
87 loadOrStoreOffset = 3;
88 size = 2;
89 loadOpcode = DLOAD;
90 constOpcode = DCONST_0;
91 } else {
92 loadOrStoreOffset = 0;
93 size = 1;
94 loadOpcode = ILOAD;
95 constOpcode = ICONST_0;
96 }
97 }
98
99 @NonNull
100 static PrimitiveType getPrimitiveType(@NonNull Class<?> aClass) {
101 for (int i = 0; i < 9; i++) {
102 if (aClass == TYPES[i]) {
103 return JAVA_TYPES[i];
104 }
105 }
106
107 throw new IllegalArgumentException("Not a primitive type: " + aClass);
108 }
109
110 @Nullable
111 public static PrimitiveType getPrimitiveType(int typeCode) {
112 int i = TYPE_CODES_STR.indexOf(typeCode);
113 return i < 0 ? null : JAVA_TYPES[i];
114 }
115
116 @Nullable
117 public static PrimitiveType getCorrespondingPrimitiveTypeIfWrapperType(@NonNull String typeDesc) {
118 for (int i = 0; i < 9; i++) {
119 if (typeDesc.equals(WRAPPER_TYPE_DESCS[i])) {
120 return JAVA_TYPES[i];
121 }
122 }
123
124 return null;
125 }
126
127 @NonNull
128 public static Class<?> getType(int typeCode) {
129 int i = TYPE_CODES_STR.indexOf((char) typeCode);
130 return TYPES[i];
131 }
132
133
134
135
136 public static int getArrayElementType(@NonNull PrimitiveType elementType) {
137 return ARRAY_ELEMENT_TYPES[elementType.index];
138 }
139
140 public char getTypeCode() {
141 return TYPE_CODES[index];
142 }
143
144 @NonNull
145 public Class<?> getType() {
146 return TYPES[index];
147 }
148
149 @NonNull
150 public String getWrapperTypeDesc() {
151 return wrapperTypeDesc;
152 }
153
154 @Override
155 void getDescriptor(@NonNull StringBuilder typeDesc) {
156 typeDesc.append(getTypeCode());
157 }
158
159 @NonNull
160 @Override
161 public String getClassName() {
162 return getType().getName();
163 }
164
165 @NonNegative
166 @Override
167 public int getSize() {
168 return size;
169 }
170
171 @Override
172 public int getOpcode(int opcode) {
173 int offset = opcode == IALOAD || opcode == IASTORE ? otherOffset : loadOrStoreOffset;
174 return opcode + offset;
175 }
176
177 @Override
178 public int getLoadOpcode() {
179 return loadOpcode;
180 }
181
182 @Override
183 public int getConstOpcode() {
184 return constOpcode;
185 }
186
187 @Override
188 public boolean equals(Object o) {
189 return this == o || o instanceof PrimitiveType && index == ((PrimitiveType) o).index;
190 }
191
192 @Override
193 public int hashCode() {
194 return 13 * index;
195 }
196 }