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