1 package mockit.asm.annotations;
2
3 import edu.umd.cs.findbugs.annotations.NonNull;
4 import edu.umd.cs.findbugs.annotations.Nullable;
5
6 import java.lang.reflect.Array;
7
8 import mockit.asm.constantPool.ConstantPoolGeneration;
9 import mockit.asm.constantPool.Item;
10 import mockit.asm.types.JavaType;
11 import mockit.asm.util.ByteVector;
12
13 import org.checkerframework.checker.index.qual.NonNegative;
14
15
16
17
18
19 public final class AnnotationVisitor {
20
21
22
23 @NonNull
24 private final ConstantPoolGeneration cp;
25
26
27
28
29 @NonNegative
30 private int attributeCount;
31
32
33
34
35
36 private final boolean named;
37
38
39
40
41
42 @NonNull
43 private final ByteVector bv;
44
45
46
47
48 @NonNegative
49 private final int offset;
50
51
52
53
54 @Nullable
55 private AnnotationVisitor next;
56
57
58
59
60 @Nullable
61 private AnnotationVisitor prev;
62
63 public AnnotationVisitor(@NonNull ConstantPoolGeneration cp, @NonNull String typeDesc) {
64 this.cp = cp;
65 named = true;
66 bv = new ByteVector();
67 bv.putShort(cp.newUTF8(typeDesc));
68 bv.putShort(0);
69 offset = 2;
70 }
71
72 private AnnotationVisitor(@NonNull AnnotationVisitor parent, boolean named) {
73 cp = parent.cp;
74 this.named = named;
75 bv = parent.bv;
76 offset = getByteLength() - 2;
77 }
78
79 @NonNegative
80 private int getByteLength() {
81 return bv.getLength();
82 }
83
84
85
86
87 public void setNext(@Nullable AnnotationVisitor next) {
88 this.next = next;
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103 void visit(@Nullable String name, @NonNull Object value) {
104 putName(name);
105
106 if (value instanceof String) {
107 putString('s', (String) value);
108 } else if (putValueWhenPrimitive(value)) {
109
110 } else if (value instanceof JavaType) {
111 putType((JavaType) value);
112 } else {
113 putElementValuesWhenArray(value);
114 }
115 }
116
117 private void putName(@Nullable String name) {
118 attributeCount++;
119
120 if (named) {
121
122 putString(name);
123 }
124 }
125
126 private boolean putValueWhenPrimitive(@NonNull Object value) {
127 if (value instanceof Boolean) {
128 putBoolean((Boolean) value);
129 } else if (value instanceof Integer) {
130 putInteger('I', (Integer) value);
131 } else if (value instanceof Double) {
132 putDouble((Double) value);
133 } else if (value instanceof Float) {
134 putFloat((Float) value);
135 } else if (value instanceof Long) {
136 putLong((Long) value);
137 } else if (value instanceof Byte) {
138 putInteger('B', (Byte) value);
139 } else if (value instanceof Character) {
140 putInteger('C', (Character) value);
141 } else if (value instanceof Short) {
142 putInteger('S', (Short) value);
143 } else {
144 return false;
145 }
146
147 return true;
148 }
149
150 private void putItem(int typeCode, @NonNull Item item) {
151 bv.put12(typeCode, item.index);
152 }
153
154 private void putBoolean(boolean value) {
155 putInteger('Z', value ? 1 : 0);
156 }
157
158 private void putInteger(int typeCode, int value) {
159 Item item = cp.newInteger(value);
160 putItem(typeCode, item);
161 }
162
163 private void putDouble(double value) {
164 Item item = cp.newDouble(value);
165 putItem('D', item);
166 }
167
168 private void putFloat(float value) {
169 Item item = cp.newFloat(value);
170 putItem('F', item);
171 }
172
173 private void putLong(long value) {
174 Item item = cp.newLong(value);
175 putItem('J', item);
176 }
177
178 private void putType(@NonNull JavaType type) {
179 String typeDescriptor = type.getDescriptor();
180 putString('c', typeDescriptor);
181 }
182
183 private void putString(int b, @NonNull String value) {
184 int itemIndex = cp.newUTF8(value);
185 bv.put12(b, itemIndex);
186 }
187
188 private void putString(@NonNull String value) {
189 int itemIndex = cp.newUTF8(value);
190 bv.putShort(itemIndex);
191 }
192
193 private void putArrayLength(@NonNegative int length) {
194 bv.put12('[', length);
195 }
196
197 private void putElementValuesWhenArray(@NonNull Object value) {
198 if (value instanceof byte[]) {
199 putArrayElementValues('B', value);
200 } else if (value instanceof boolean[]) {
201 putArrayElementValues('Z', value);
202 } else if (value instanceof short[]) {
203 putArrayElementValues('S', value);
204 } else if (value instanceof char[]) {
205 putArrayElementValues('C', value);
206 } else if (value instanceof int[]) {
207 putArrayElementValues('I', value);
208 } else if (value instanceof long[]) {
209 putArrayElementValues('J', value);
210 } else if (value instanceof float[]) {
211 putArrayElementValues('F', value);
212 } else if (value instanceof double[]) {
213 putArrayElementValues('D', value);
214 }
215 }
216
217 private void putArrayElementValues(char elementType, @NonNull Object array) {
218 int length = Array.getLength(array);
219 putArrayLength(length);
220
221 for (int i = 0; i < length; i++) {
222 switch (elementType) {
223 case 'J': {
224 long value = Array.getLong(array, i);
225 putLong(value);
226 break;
227 }
228 case 'F': {
229 float value = Array.getFloat(array, i);
230 putFloat(value);
231 break;
232 }
233 case 'D': {
234 double value = Array.getDouble(array, i);
235 putDouble(value);
236 break;
237 }
238 case 'Z': {
239 boolean value = Array.getBoolean(array, i);
240 putBoolean(value);
241 break;
242 }
243 default: {
244 int value = Array.getInt(array, i);
245 putInteger(elementType, value);
246 break;
247 }
248 }
249 }
250 }
251
252
253
254
255
256
257
258
259
260
261
262 void visitEnum(@Nullable String name, @NonNull String desc, @NonNull String value) {
263 putName(name);
264 putString('e', desc);
265 putString(value);
266 }
267
268
269
270
271
272
273
274
275
276
277
278 @NonNull
279 AnnotationVisitor visitAnnotation(@Nullable String name, @NonNull String desc) {
280 putName(name);
281
282
283 putString('@', desc);
284 bv.putShort(0);
285
286 return new AnnotationVisitor(this, true);
287 }
288
289
290
291
292
293
294
295
296
297
298
299 @NonNull
300 AnnotationVisitor visitArray(@Nullable String name) {
301 putName(name);
302
303
304 putArrayLength(0);
305
306 return new AnnotationVisitor(this, false);
307 }
308
309
310
311
312 @SuppressWarnings("NumericCastThatLosesPrecision")
313 void visitEnd() {
314 byte[] data = bv.getData();
315 data[offset] = (byte) (attributeCount >>> 8);
316 data[offset + 1] = (byte) attributeCount;
317 }
318
319
320
321
322 @NonNegative
323 public int getSize() {
324 int size = 0;
325 AnnotationVisitor annotation = this;
326
327 while (annotation != null) {
328 size += annotation.getByteLength();
329 annotation = annotation.next;
330 }
331
332 return size;
333 }
334
335
336
337
338 public void put(@NonNull ByteVector out) {
339 AnnotationVisitor aw = this;
340 AnnotationVisitor last = null;
341 int n = 0;
342 int size = 2;
343
344 while (aw != null) {
345 n++;
346 size += aw.getByteLength();
347 aw.prev = last;
348 last = aw;
349 aw = aw.next;
350 }
351
352 out.putInt(size);
353 out.putShort(n);
354 putFromLastToFirst(out, last);
355 }
356
357 private static void putFromLastToFirst(@NonNull ByteVector out, @Nullable AnnotationVisitor aw) {
358 while (aw != null) {
359 out.putByteVector(aw.bv);
360 aw = aw.prev;
361 }
362 }
363
364
365
366
367 public static void put(@NonNull ByteVector out, @NonNull AnnotationVisitor[] anns) {
368 putNumberAndSizeOfAnnotations(out, anns);
369
370 for (AnnotationVisitor ann : anns) {
371 AnnotationVisitor last = putNumberOfAnnotations(out, ann);
372 putFromLastToFirst(out, last);
373 }
374 }
375
376 private static void putNumberAndSizeOfAnnotations(@NonNull ByteVector out, @NonNull AnnotationVisitor[] anns) {
377 int numAnns = anns.length;
378 int size = 1 + 2 * numAnns;
379
380 for (AnnotationVisitor aw : anns) {
381 if (aw != null) {
382 size += aw.getSize();
383 }
384 }
385
386 out.putInt(size).putByte(numAnns);
387 }
388
389 @Nullable
390 private static AnnotationVisitor putNumberOfAnnotations(@NonNull ByteVector out, @Nullable AnnotationVisitor aw) {
391 AnnotationVisitor last = null;
392 int n = 0;
393
394 while (aw != null) {
395 n++;
396 aw.prev = last;
397 last = aw;
398 aw = aw.next;
399 }
400
401 out.putShort(n);
402 return last;
403 }
404 }