1
2
3
4
5
6 package mockit.asm.util;
7
8 import static mockit.asm.jvmConstants.ConstantPoolTypes.CLASS;
9 import static mockit.asm.jvmConstants.ConstantPoolTypes.DOUBLE;
10 import static mockit.asm.jvmConstants.ConstantPoolTypes.DYNAMIC;
11 import static mockit.asm.jvmConstants.ConstantPoolTypes.FIELD_REF;
12 import static mockit.asm.jvmConstants.ConstantPoolTypes.FLOAT;
13 import static mockit.asm.jvmConstants.ConstantPoolTypes.IMETHOD_REF;
14 import static mockit.asm.jvmConstants.ConstantPoolTypes.INTEGER;
15 import static mockit.asm.jvmConstants.ConstantPoolTypes.INVOKE_DYNAMIC;
16 import static mockit.asm.jvmConstants.ConstantPoolTypes.LONG;
17 import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_HANDLE;
18 import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_REF;
19 import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_TYPE;
20 import static mockit.asm.jvmConstants.ConstantPoolTypes.MODULE;
21 import static mockit.asm.jvmConstants.ConstantPoolTypes.NAME_TYPE;
22 import static mockit.asm.jvmConstants.ConstantPoolTypes.PACKAGE;
23 import static mockit.asm.jvmConstants.ConstantPoolTypes.STRING;
24 import static mockit.asm.jvmConstants.ConstantPoolTypes.UTF8;
25
26 import edu.umd.cs.findbugs.annotations.NonNull;
27 import edu.umd.cs.findbugs.annotations.Nullable;
28
29 import mockit.asm.constantPool.DynamicItem;
30 import mockit.asm.jvmConstants.ConstantPoolTypes;
31 import mockit.asm.types.JavaType;
32 import mockit.asm.types.MethodType;
33 import mockit.asm.types.ReferenceType;
34
35 import org.checkerframework.checker.index.qual.NonNegative;
36
37 public class BytecodeReader {
38
39
40
41 @NonNull
42 public final byte[] code;
43
44
45
46
47
48 @NonNull
49 public final int[] items;
50
51
52
53
54
55
56
57 @NonNull
58 private final String[] strings;
59
60
61
62
63 @NonNull
64 private final char[] buf;
65
66
67
68
69 @NonNegative
70 public int codeIndex;
71
72 protected BytecodeReader(@NonNull byte[] code) {
73 this.code = code;
74 codeIndex = 8;
75
76 int itemCount = readUnsignedShort();
77 items = new int[itemCount];
78 strings = new String[itemCount];
79
80 int maxStringSize = readConstantPoolItems();
81 buf = new char[maxStringSize];
82 }
83
84 @NonNegative
85 private int readConstantPoolItems() {
86 int maxStringSize = 0;
87
88 for (int itemIndex = 1; itemIndex < items.length; itemIndex++) {
89 int itemType = readSignedByte();
90 items[itemIndex] = codeIndex;
91 int itemSize = getItemSize(itemType);
92
93 if (itemType == LONG || itemType == DOUBLE) {
94 itemIndex++;
95 } else if (itemType == UTF8 && itemSize > maxStringSize) {
96 maxStringSize = itemSize;
97 }
98
99 codeIndex += itemSize - 1;
100 }
101
102 return maxStringSize;
103 }
104
105 @NonNegative
106 private int getItemSize(int itemType) {
107 switch (itemType) {
108 case FIELD_REF:
109 case METHOD_REF:
110 case IMETHOD_REF:
111 case INTEGER:
112 case FLOAT:
113 case NAME_TYPE:
114 case DYNAMIC:
115 case INVOKE_DYNAMIC:
116 return 5;
117 case LONG:
118 case DOUBLE:
119 return 9;
120 case UTF8:
121 return 3 + readUnsignedShort(codeIndex);
122 case METHOD_HANDLE:
123 return 4;
124 case MODULE:
125 case PACKAGE:
126 case CLASS:
127 case STRING:
128 case METHOD_TYPE:
129 return 3;
130 default:
131 throw new IllegalArgumentException("Unknown item type, cannot determine size: " + itemType);
132 }
133 }
134
135 protected BytecodeReader(@NonNull BytecodeReader another) {
136 code = another.code;
137 items = another.items;
138 strings = another.strings;
139 buf = another.buf;
140 codeIndex = another.codeIndex;
141 }
142
143
144
145
146
147
148 @NonNegative
149 public final int readUnsignedByte() {
150 return code[codeIndex++] & 0xFF;
151 }
152
153
154
155
156
157
158
159
160
161 @NonNegative
162 protected final int readUnsignedByte(@NonNegative int u1CodeIndex) {
163 return code[u1CodeIndex] & 0xFF;
164 }
165
166
167
168
169
170
171 public final int readSignedByte() {
172 return code[codeIndex++];
173 }
174
175 protected final char readChar(@NonNegative int s4CodeIndex) {
176 return (char) readInt(s4CodeIndex);
177 }
178
179 protected final boolean readBoolean(@NonNegative int s4CodeIndex) {
180 return readInt(s4CodeIndex) != 0;
181 }
182
183
184
185
186
187
188 @NonNegative
189 public final int readUnsignedShort() {
190 byte[] b = code;
191 int i = codeIndex;
192 int byte0 = (b[i] & 0xFF) << 8;
193 i++;
194 int byte1 = b[i] & 0xFF;
195 i++;
196 codeIndex = i;
197 return byte0 | byte1;
198 }
199
200
201
202
203
204
205
206
207
208 @NonNegative
209 protected final int readUnsignedShort(@NonNegative int u2CodeIndex) {
210 byte[] b = code;
211 int byte0 = (b[u2CodeIndex] & 0xFF) << 8;
212 int byte1 = b[u2CodeIndex + 1] & 0xFF;
213 return byte0 | byte1;
214 }
215
216
217
218
219
220
221 protected final short readShort() {
222
223 return (short) readUnsignedShort();
224 }
225
226
227
228
229
230
231
232
233
234 protected final short readShort(@NonNegative int u2CodeIndex) {
235
236 return (short) readUnsignedShort(u2CodeIndex);
237 }
238
239
240
241
242
243
244 public final int readInt() {
245 byte[] b = code;
246 int i = codeIndex;
247 int byte0 = (b[i] & 0xFF) << 24;
248 i++;
249 int byte1 = (b[i] & 0xFF) << 16;
250 i++;
251 int byte2 = (b[i] & 0xFF) << 8;
252 i++;
253 int byte3 = b[i] & 0xFF;
254 i++;
255 codeIndex = i;
256 return byte0 | byte1 | byte2 | byte3;
257 }
258
259
260
261
262
263
264
265
266
267 protected final int readInt(@NonNegative int s4CodeIndex) {
268 byte[] b = code;
269 return (b[s4CodeIndex] & 0xFF) << 24 | (b[s4CodeIndex + 1] & 0xFF) << 16 | (b[s4CodeIndex + 2] & 0xFF) << 8
270 | b[s4CodeIndex + 3] & 0xFF;
271 }
272
273
274
275
276
277
278 public final long readLong() {
279 long l1 = readInt();
280 long l0 = readInt() & 0xFFFFFFFFL;
281 return l1 << 32 | l0;
282 }
283
284
285
286
287
288
289
290
291
292 protected final long readLong(@NonNegative int s8CodeIndex) {
293 long l1 = readInt(s8CodeIndex);
294 long l0 = readInt(s8CodeIndex + 4) & 0xFFFFFFFFL;
295 return l1 << 32 | l0;
296 }
297
298 public final double readDouble() {
299 long bits = readLong();
300 return Double.longBitsToDouble(bits);
301 }
302
303 protected final double readDouble(@NonNegative int s8CodeIndex) {
304 long bits = readLong(s8CodeIndex);
305 return Double.longBitsToDouble(bits);
306 }
307
308 public final float readFloat() {
309 int bits = readInt();
310 return Float.intBitsToFloat(bits);
311 }
312
313 protected final float readFloat(@NonNegative int s4CodeIndex) {
314 int bits = readInt(s4CodeIndex);
315 return Float.intBitsToFloat(bits);
316 }
317
318
319
320
321
322
323
324
325
326 @NonNull
327 @SuppressWarnings("CharUsedInArithmeticContext")
328 private String readUTF(@NonNegative int itemIndex) {
329 int startIndex = items[itemIndex];
330 int utfLen = readUnsignedShort(startIndex);
331 startIndex += 2;
332 int endIndex = startIndex + utfLen;
333 int strLen = 0;
334 int st = 0;
335 @SuppressWarnings("QuestionableName")
336 char cc = 0;
337
338 while (startIndex < endIndex) {
339 int c = code[startIndex];
340 startIndex++;
341
342 if (st == 0) {
343 c &= 0xFF;
344
345 if (c < 0x80) {
346 buf[strLen] = (char) c;
347 strLen++;
348 } else if (c < 0xE0 && c > 0xBF) {
349 cc = (char) (c & 0x1F);
350 st = 1;
351 } else {
352 cc = (char) (c & 0x0F);
353 st = 2;
354 }
355 } else if (st == 1) {
356 buf[strLen] = (char) (cc << 6 | c & 0x3F);
357 strLen++;
358 st = 0;
359 } else {
360 cc = (char) (cc << 6 | c & 0x3F);
361 st = 1;
362 }
363 }
364
365 return new String(buf, 0, strLen);
366 }
367
368
369
370
371
372
373
374 @Nullable
375 protected final String readUTF8() {
376 int itemIndex = readUnsignedShort();
377
378 if (itemIndex == 0) {
379 return null;
380 }
381
382 return readString(itemIndex);
383 }
384
385
386
387
388
389
390
391
392
393
394
395 @Nullable
396 protected final String readUTF8(@NonNegative int u2CodeIndex) {
397 if (u2CodeIndex == 0) {
398 return null;
399 }
400
401 int itemIndex = readUnsignedShort(u2CodeIndex);
402
403 if (itemIndex == 0) {
404 return null;
405 }
406
407 return readString(itemIndex);
408 }
409
410
411
412
413
414
415 @NonNull
416 public final String readNonnullUTF8() {
417 int itemIndex = readUnsignedShort();
418 return readString(itemIndex);
419 }
420
421
422
423
424
425
426
427
428
429 @NonNull
430 public final String readNonnullUTF8(@NonNegative int u2CodeIndex) {
431 int itemIndex = readUnsignedShort(u2CodeIndex);
432 return readString(itemIndex);
433 }
434
435
436
437
438
439
440
441
442
443 @NonNull
444 public final String readString(@NonNegative int itemIndex) {
445 String cachedString = strings[itemIndex];
446
447 if (cachedString != null) {
448 return cachedString;
449 }
450
451 String newString = readUTF(itemIndex);
452 strings[itemIndex] = newString;
453 return newString;
454 }
455
456
457
458
459
460
461 @NonNull
462 public final Object readConstItem() {
463 int constIndex = readUnsignedShort();
464 return readConst(constIndex);
465 }
466
467 @NonNull
468 protected final Object readConstItem(@NonNegative int u2CodeIndex) {
469 int itemIndex = readUnsignedShort(u2CodeIndex);
470 return readConst(itemIndex);
471 }
472
473
474
475
476
477
478
479
480
481
482 @NonNull
483 protected final Object readConst(@NonNegative int itemIndex) {
484 int constCodeIndex = items[itemIndex];
485 byte itemType = code[constCodeIndex - 1];
486
487 switch (itemType) {
488 case INTEGER:
489 return readInt(constCodeIndex);
490 case FLOAT:
491 return readFloat(constCodeIndex);
492 case LONG:
493 return readLong(constCodeIndex);
494 case DOUBLE:
495 return readDouble(constCodeIndex);
496 case STRING:
497 return readNonnullUTF8(constCodeIndex);
498 case CLASS:
499 String typeDesc = readNonnullUTF8(constCodeIndex);
500 return ReferenceType.createFromInternalName(typeDesc);
501 case METHOD_TYPE:
502 String methodDesc = readNonnullUTF8(constCodeIndex);
503 return MethodType.create(methodDesc);
504 case DYNAMIC: {
505 int bsmStartIndex = readUnsignedShort(constCodeIndex);
506 int nameIndex = readItem(constCodeIndex + 2);
507 String name = readNonnullUTF8(nameIndex);
508 String desc = readNonnullUTF8(nameIndex + 2);
509 DynamicItem dynamicItem = new DynamicItem(itemIndex);
510 dynamicItem.set(ConstantPoolTypes.DYNAMIC, name, desc, bsmStartIndex);
511 return dynamicItem;
512 }
513 case METHOD_HANDLE:
514 return readMethodHandle(constCodeIndex);
515 default:
516 throw new IllegalArgumentException("Unknown const item type code: " + itemType);
517 }
518 }
519
520 @NonNull
521 public final MethodHandle readMethodHandle() {
522 int itemIndex = readUnsignedShort();
523 return readMethodHandle(items[itemIndex]);
524 }
525
526 @NonNull
527 protected final MethodHandle readMethodHandleItem(@NonNegative int bsmCodeIndex) {
528 int itemIndex = readUnsignedShort(bsmCodeIndex);
529 return readMethodHandle(items[itemIndex]);
530 }
531
532 @NonNull
533 private MethodHandle readMethodHandle(@NonNegative int bsmCodeIndex) {
534 int tag = readUnsignedByte(bsmCodeIndex);
535 if (tag < MethodHandle.Tag.TAG_GETFIELD || tag > MethodHandle.Tag.TAG_INVOKEINTERFACE) {
536 throw new IllegalArgumentException("Illegal method-handle tag: " + tag);
537 }
538
539 int classIndex = readItem(bsmCodeIndex + 1);
540 String owner = readNonnullClass(classIndex);
541
542 int nameIndex = readItem(classIndex + 2);
543 String name = readNonnullUTF8(nameIndex);
544 String desc = readNonnullUTF8(nameIndex + 2);
545
546 return new MethodHandle(tag, owner, name, desc);
547 }
548
549
550
551
552
553
554 @Nullable
555 protected final String readClass() {
556 int itemCodeIndex = readItem();
557 return readUTF8(itemCodeIndex);
558 }
559
560
561
562
563
564
565 @NonNull
566 public final String readNonnullClass() {
567 int itemCodeIndex = readItem();
568 return readNonnullUTF8(itemCodeIndex);
569 }
570
571 @NonNull
572 public final String readNonnullClass(@NonNegative int u2CodeIndex) {
573 int itemCodeIndex = readItem(u2CodeIndex);
574 return readNonnullUTF8(itemCodeIndex);
575 }
576
577
578
579
580
581
582 @NonNegative
583 public final int readItem() {
584 int itemIndex = readUnsignedShort();
585 return items[itemIndex];
586 }
587
588 @NonNegative
589 public final int readItem(@NonNegative int u2CodeIndex) {
590 int itemIndex = readUnsignedShort(u2CodeIndex);
591 return items[itemIndex];
592 }
593 }