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