• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / jmockit1 / 496

15 Nov 2025 05:33PM UTC coverage: 72.192% (-0.008%) from 72.2%
496

push

github

web-flow
Merge pull request #412 from hazendaz/renovate/major-spring-core

Update spring core to v7 (major)

5677 of 8360 branches covered (67.91%)

Branch coverage included in aggregate %.

11922 of 16018 relevant lines covered (74.43%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.27
/main/src/main/java/mockit/asm/util/BytecodeReader.java
1
/*
2
 * MIT License
3
 * Copyright (c) 2006-2025 JMockit developers
4
 * See LICENSE file for full license text.
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
     * The class to be parsed. <em>The content of this array must not be modified.</em>
40
     */
41
    @NonNull
42
    public final byte[] code;
43

44
    /**
45
     * The start index of each constant pool item in {@link #code}, plus one. The one byte offset skips the constant
46
     * pool item tag that indicates its type.
47
     */
48
    @NonNull
49
    public final int[] items;
50

51
    /**
52
     * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing of a given
53
     * CONSTANT_Utf8 constant pool item, which GREATLY improves performances (by a factor 2 to 3). This caching strategy
54
     * could be extended to all constant pool items, but its benefit would not be so great for these items (because they
55
     * are much less expensive to parse than CONSTANT_Utf8 items).
56
     */
57
    @NonNull
58
    private final String[] strings;
59

60
    /**
61
     * The buffer used to read strings.
62
     */
63
    @NonNull
64
    private final char[] buf;
65

66
    /**
67
     * The next index at {@link #code} to be read.
68
     */
69
    @NonNegative
70
    public int codeIndex;
71

72
    protected BytecodeReader(@NonNull byte[] code) {
1✔
73
        this.code = code;
1✔
74
        codeIndex = 8;
1✔
75

76
        int itemCount = readUnsignedShort();
1✔
77
        items = new int[itemCount];
1✔
78
        strings = new String[itemCount];
1✔
79

80
        int maxStringSize = readConstantPoolItems();
1✔
81
        buf = new char[maxStringSize];
1✔
82
    }
1✔
83

84
    @NonNegative
85
    private int readConstantPoolItems() {
86
        int maxStringSize = 0;
1✔
87

88
        for (int itemIndex = 1; itemIndex < items.length; itemIndex++) {
1✔
89
            int itemType = readSignedByte();
1✔
90
            items[itemIndex] = codeIndex;
1✔
91
            int itemSize = getItemSize(itemType);
1✔
92

93
            if (itemType == LONG || itemType == DOUBLE) {
1✔
94
                itemIndex++;
1✔
95
            } else if (itemType == UTF8 && itemSize > maxStringSize) {
1✔
96
                maxStringSize = itemSize;
1✔
97
            }
98

99
            codeIndex += itemSize - 1;
1✔
100
        }
101

102
        return maxStringSize;
1✔
103
    }
104

105
    @NonNegative
106
    private int getItemSize(int itemType) {
107
        switch (itemType) {
1!
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;
1✔
117
            case LONG:
118
            case DOUBLE:
119
                return 9;
1✔
120
            case UTF8:
121
                return 3 + readUnsignedShort(codeIndex);
1✔
122
            case METHOD_HANDLE:
123
                return 4;
1✔
124
            case MODULE:
125
            case PACKAGE:
126
            case CLASS:
127
            case STRING:
128
            case METHOD_TYPE:
129
                return 3;
1✔
130
            default:
131
                throw new IllegalArgumentException("Unknown item type, cannot determine size: " + itemType);
×
132
        }
133
    }
134

135
    protected BytecodeReader(@NonNull BytecodeReader another) {
1✔
136
        code = another.code;
1✔
137
        items = another.items;
1✔
138
        strings = another.strings;
1✔
139
        buf = another.buf;
1✔
140
        codeIndex = another.codeIndex;
1✔
141
    }
1✔
142

143
    /**
144
     * Reads an unsigned <code>byte</code> value in {@link #code}, incrementing {@link #codeIndex} by 1.
145
     *
146
     * @return the int
147
     */
148
    @NonNegative
149
    public final int readUnsignedByte() {
150
        return code[codeIndex++] & 0xFF;
1✔
151
    }
152

153
    /**
154
     * Reads an unsigned byte value in {@link #code}.
155
     *
156
     * @param u1CodeIndex
157
     *            the start index of the value to be read in {@link #code}
158
     *
159
     * @return the int
160
     */
161
    @NonNegative
162
    protected final int readUnsignedByte(@NonNegative int u1CodeIndex) {
163
        return code[u1CodeIndex] & 0xFF;
1✔
164
    }
165

166
    /**
167
     * Reads a signed <code>byte</code> value in {@link #code}, incrementing {@link #codeIndex} by 1.
168
     *
169
     * @return the int
170
     */
171
    public final int readSignedByte() {
172
        return code[codeIndex++];
1✔
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
     * Reads an unsigned short value in {@link #code}, incrementing {@link #codeIndex} by 2.
185
     *
186
     * @return the int
187
     */
188
    @NonNegative
189
    public final int readUnsignedShort() {
190
        byte[] b = code;
1✔
191
        int i = codeIndex;
1✔
192
        int byte0 = (b[i] & 0xFF) << 8;
1✔
193
        i++;
1✔
194
        int byte1 = b[i] & 0xFF;
1✔
195
        i++;
1✔
196
        codeIndex = i;
1✔
197
        return byte0 | byte1;
1✔
198
    }
199

200
    /**
201
     * Reads an unsigned short value in {@link #code}.
202
     *
203
     * @param u2CodeIndex
204
     *            the start index of the value to be read in {@link #code}
205
     *
206
     * @return the int
207
     */
208
    @NonNegative
209
    protected final int readUnsignedShort(@NonNegative int u2CodeIndex) {
210
        byte[] b = code;
1✔
211
        int byte0 = (b[u2CodeIndex] & 0xFF) << 8;
1✔
212
        int byte1 = b[u2CodeIndex + 1] & 0xFF;
1✔
213
        return byte0 | byte1;
1✔
214
    }
215

216
    /**
217
     * Reads a signed <code>short</code> value in {@link #code}, incrementing {@link #codeIndex} by 2.
218
     *
219
     * @return the short
220
     */
221
    protected final short readShort() {
222
        // noinspection NumericCastThatLosesPrecision
223
        return (short) readUnsignedShort();
1✔
224
    }
225

226
    /**
227
     * Reads a signed short value in {@link #code}.
228
     *
229
     * @param u2CodeIndex
230
     *            the start index of the value to be read in {@link #code}
231
     *
232
     * @return the short
233
     */
234
    protected final short readShort(@NonNegative int u2CodeIndex) {
235
        // noinspection NumericCastThatLosesPrecision
236
        return (short) readUnsignedShort(u2CodeIndex);
1✔
237
    }
238

239
    /**
240
     * Reads a signed <code>int</code> value in {@link #code}, incrementing {@link #codeIndex} by 4.
241
     *
242
     * @return the int
243
     */
244
    public final int readInt() {
245
        byte[] b = code;
1✔
246
        int i = codeIndex;
1✔
247
        int byte0 = (b[i] & 0xFF) << 24;
1✔
248
        i++;
1✔
249
        int byte1 = (b[i] & 0xFF) << 16;
1✔
250
        i++;
1✔
251
        int byte2 = (b[i] & 0xFF) << 8;
1✔
252
        i++;
1✔
253
        int byte3 = b[i] & 0xFF;
1✔
254
        i++;
1✔
255
        codeIndex = i;
1✔
256
        return byte0 | byte1 | byte2 | byte3;
1✔
257
    }
258

259
    /**
260
     * Reads a signed int value in {@link #code}.
261
     *
262
     * @param s4CodeIndex
263
     *            the start index of the value to be read in {@link #code}
264
     *
265
     * @return the int
266
     */
267
    protected final int readInt(@NonNegative int s4CodeIndex) {
268
        byte[] b = code;
1✔
269
        return (b[s4CodeIndex] & 0xFF) << 24 | (b[s4CodeIndex + 1] & 0xFF) << 16 | (b[s4CodeIndex + 2] & 0xFF) << 8
1✔
270
                | b[s4CodeIndex + 3] & 0xFF;
271
    }
272

273
    /**
274
     * Reads a signed long value in {@link #code}, incrementing {@link #codeIndex} by 8.
275
     *
276
     * @return the long
277
     */
278
    public final long readLong() {
279
        long l1 = readInt();
1✔
280
        long l0 = readInt() & 0xFFFFFFFFL;
1✔
281
        return l1 << 32 | l0;
1✔
282
    }
283

284
    /**
285
     * Reads a signed long value in {@link #code}.
286
     *
287
     * @param s8CodeIndex
288
     *            the start index of the value to be read in {@link #code}
289
     *
290
     * @return the long
291
     */
292
    protected final long readLong(@NonNegative int s8CodeIndex) {
293
        long l1 = readInt(s8CodeIndex);
1✔
294
        long l0 = readInt(s8CodeIndex + 4) & 0xFFFFFFFFL;
1✔
295
        return l1 << 32 | l0;
1✔
296
    }
297

298
    public final double readDouble() {
299
        long bits = readLong();
1✔
300
        return Double.longBitsToDouble(bits);
1✔
301
    }
302

303
    protected final double readDouble(@NonNegative int s8CodeIndex) {
304
        long bits = readLong(s8CodeIndex);
1✔
305
        return Double.longBitsToDouble(bits);
1✔
306
    }
307

308
    public final float readFloat() {
309
        int bits = readInt();
1✔
310
        return Float.intBitsToFloat(bits);
1✔
311
    }
312

313
    protected final float readFloat(@NonNegative int s4CodeIndex) {
314
        int bits = readInt(s4CodeIndex);
1✔
315
        return Float.intBitsToFloat(bits);
1✔
316
    }
317

318
    /**
319
     * Reads an UTF8 string in {@link #code}.
320
     *
321
     * @param itemIndex
322
     *            index in {@link #items} for the UTF8 string to be read
323
     *
324
     * @return the string
325
     */
326
    @NonNull
327
    @SuppressWarnings("CharUsedInArithmeticContext")
328
    private String readUTF(@NonNegative int itemIndex) {
329
        int startIndex = items[itemIndex];
1✔
330
        int utfLen = readUnsignedShort(startIndex);
1✔
331
        startIndex += 2;
1✔
332
        int endIndex = startIndex + utfLen;
1✔
333
        int strLen = 0;
1✔
334
        int st = 0;
1✔
335
        @SuppressWarnings("QuestionableName")
336
        char cc = 0;
1✔
337

338
        while (startIndex < endIndex) {
1✔
339
            int c = code[startIndex];
1✔
340
            startIndex++;
1✔
341

342
            if (st == 0) {
1✔
343
                c &= 0xFF;
1✔
344

345
                if (c < 0x80) { // 0xxxxxxx
1✔
346
                    buf[strLen] = (char) c;
1✔
347
                    strLen++;
1✔
348
                } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx
1!
349
                    cc = (char) (c & 0x1F);
1✔
350
                    st = 1;
1✔
351
                } else { // 1110 xxxx 10xx xxxx 10xx xxxx
352
                    cc = (char) (c & 0x0F);
×
353
                    st = 2;
×
354
                }
355
            } else if (st == 1) { // byte 2 of 2-byte char or byte 3 of 3-byte char
1!
356
                buf[strLen] = (char) (cc << 6 | c & 0x3F);
1✔
357
                strLen++;
1✔
358
                st = 0;
1✔
359
            } else { // byte 2 of 3-byte char
360
                cc = (char) (cc << 6 | c & 0x3F);
×
361
                st = 1;
×
362
            }
363
        }
1✔
364

365
        return new String(buf, 0, strLen);
1✔
366
    }
367

368
    /**
369
     * Reads an UTF8 string constant pool item in {@link #code}, incrementing {@link #codeIndex} by 2.
370
     *
371
     * @return the String corresponding to the UTF8 item, or <code>null</code> if {@link #codeIndex} points to an item
372
     *         whose value is zero
373
     */
374
    @Nullable
375
    protected final String readUTF8() {
376
        int itemIndex = readUnsignedShort();
1✔
377

378
        if (itemIndex == 0) {
1✔
379
            return null;
1✔
380
        }
381

382
        return readString(itemIndex);
1✔
383
    }
384

385
    /**
386
     * Reads an UTF8 string constant pool item in {@link #code}.
387
     *
388
     * @param u2CodeIndex
389
     *            the index of an unsigned short value in {@link #code}, whose value is the index of an UTF8 constant
390
     *            pool item
391
     *
392
     * @return the String corresponding to the UTF8 item, or <code>null</code> if index is zero or points to an item
393
     *         whose value is zero
394
     */
395
    @Nullable
396
    protected final String readUTF8(@NonNegative int u2CodeIndex) {
397
        if (u2CodeIndex == 0) {
1✔
398
            return null;
1✔
399
        }
400

401
        int itemIndex = readUnsignedShort(u2CodeIndex);
1✔
402

403
        if (itemIndex == 0) {
1!
404
            return null;
×
405
        }
406

407
        return readString(itemIndex);
1✔
408
    }
409

410
    /**
411
     * Reads the index of an UTF8 item in {@link #code}, incrementing {@link #codeIndex} by 2.
412
     *
413
     * @return the UTF8 string found in {@link #strings} at that index
414
     */
415
    @NonNull
416
    public final String readNonnullUTF8() {
417
        int itemIndex = readUnsignedShort();
1✔
418
        return readString(itemIndex);
1✔
419
    }
420

421
    /**
422
     * Reads the index of an UTF8 item in {@link #code}.
423
     *
424
     * @param u2CodeIndex
425
     *            the u 2 code index
426
     *
427
     * @return the UTF8 string found in {@link #strings} at that index
428
     */
429
    @NonNull
430
    public final String readNonnullUTF8(@NonNegative int u2CodeIndex) {
431
        int itemIndex = readUnsignedShort(u2CodeIndex);
1✔
432
        return readString(itemIndex);
1✔
433
    }
434

435
    /**
436
     * Reads a string in {@link #strings} at the given index.
437
     *
438
     * @param itemIndex
439
     *            the item index
440
     *
441
     * @return the string
442
     */
443
    @NonNull
444
    public final String readString(@NonNegative int itemIndex) {
445
        String cachedString = strings[itemIndex];
1✔
446

447
        if (cachedString != null) {
1✔
448
            return cachedString;
1✔
449
        }
450

451
        String newString = readUTF(itemIndex);
1✔
452
        strings[itemIndex] = newString;
1✔
453
        return newString;
1✔
454
    }
455

456
    /**
457
     * Reads the index of a constant item in {@link #code}, incrementing {@link #codeIndex} by 2.
458
     *
459
     * @return the UTF8 string found in {@link #strings} at that index
460
     */
461
    @NonNull
462
    public final Object readConstItem() {
463
        int constIndex = readUnsignedShort();
1✔
464
        return readConst(constIndex);
1✔
465
    }
466

467
    @NonNull
468
    protected final Object readConstItem(@NonNegative int u2CodeIndex) {
469
        int itemIndex = readUnsignedShort(u2CodeIndex);
1✔
470
        return readConst(itemIndex);
1✔
471
    }
472

473
    /**
474
     * Reads a numeric or string constant pool item in {@link #code}.
475
     *
476
     * @param itemIndex
477
     *            the index of a constant pool item
478
     *
479
     * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link JavaType} or
480
     *         {@link MethodHandle} corresponding to the given constant pool item
481
     */
482
    @NonNull
483
    protected final Object readConst(@NonNegative int itemIndex) {
484
        int constCodeIndex = items[itemIndex];
1✔
485
        byte itemType = code[constCodeIndex - 1];
1✔
486

487
        switch (itemType) {
1!
488
            case INTEGER:
489
                return readInt(constCodeIndex);
1✔
490
            case FLOAT:
491
                return readFloat(constCodeIndex);
1✔
492
            case LONG:
493
                return readLong(constCodeIndex);
1✔
494
            case DOUBLE:
495
                return readDouble(constCodeIndex);
1✔
496
            case STRING:
497
                return readNonnullUTF8(constCodeIndex);
1✔
498
            case CLASS:
499
                String typeDesc = readNonnullUTF8(constCodeIndex);
1✔
500
                return ReferenceType.createFromInternalName(typeDesc);
1✔
501
            case METHOD_TYPE:
502
                String methodDesc = readNonnullUTF8(constCodeIndex);
1✔
503
                return MethodType.create(methodDesc);
1✔
504
            case DYNAMIC: {
505
                int bsmStartIndex = readUnsignedShort(constCodeIndex);
1✔
506
                int nameIndex = readItem(constCodeIndex + 2);
1✔
507
                String name = readNonnullUTF8(nameIndex);
1✔
508
                String desc = readNonnullUTF8(nameIndex + 2);
1✔
509
                DynamicItem dynamicItem = new DynamicItem(itemIndex);
1✔
510
                dynamicItem.set(ConstantPoolTypes.DYNAMIC, name, desc, bsmStartIndex);
1✔
511
                return dynamicItem;
1✔
512
            }
513
            case METHOD_HANDLE:
514
                return readMethodHandle(constCodeIndex);
1✔
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();
1✔
523
        return readMethodHandle(items[itemIndex]);
1✔
524
    }
525

526
    @NonNull
527
    protected final MethodHandle readMethodHandleItem(@NonNegative int bsmCodeIndex) {
528
        int itemIndex = readUnsignedShort(bsmCodeIndex);
1✔
529
        return readMethodHandle(items[itemIndex]);
1✔
530
    }
531

532
    @NonNull
533
    private MethodHandle readMethodHandle(@NonNegative int bsmCodeIndex) {
534
        int tag = readUnsignedByte(bsmCodeIndex);
1✔
535
        if (tag < MethodHandle.Tag.TAG_GETFIELD || tag > MethodHandle.Tag.TAG_INVOKEINTERFACE) {
1!
536
            throw new IllegalArgumentException("Illegal method-handle tag: " + tag);
×
537
        }
538

539
        int classIndex = readItem(bsmCodeIndex + 1);
1✔
540
        String owner = readNonnullClass(classIndex);
1✔
541

542
        int nameIndex = readItem(classIndex + 2);
1✔
543
        String name = readNonnullUTF8(nameIndex);
1✔
544
        String desc = readNonnullUTF8(nameIndex + 2);
1✔
545

546
        return new MethodHandle(tag, owner, name, desc);
1✔
547
    }
548

549
    /**
550
     * Reads the class name from the constant pool, incrementing {@link #codeIndex} by 2.
551
     *
552
     * @return the string
553
     */
554
    @Nullable
555
    protected final String readClass() {
556
        int itemCodeIndex = readItem();
1✔
557
        return readUTF8(itemCodeIndex);
1✔
558
    }
559

560
    /**
561
     * Reads a class descriptor in {@link #code}, incrementing {@link #codeIndex} by 2.
562
     *
563
     * @return the string
564
     */
565
    @NonNull
566
    public final String readNonnullClass() {
567
        int itemCodeIndex = readItem();
1✔
568
        return readNonnullUTF8(itemCodeIndex);
1✔
569
    }
570

571
    @NonNull
572
    public final String readNonnullClass(@NonNegative int u2CodeIndex) {
573
        int itemCodeIndex = readItem(u2CodeIndex);
1✔
574
        return readNonnullUTF8(itemCodeIndex);
1✔
575
    }
576

577
    /**
578
     * Reads an item index in {@link #code}, incrementing {@link #codeIndex} by 2.
579
     *
580
     * @return the item at that index in {@link #items}
581
     */
582
    @NonNegative
583
    public final int readItem() {
584
        int itemIndex = readUnsignedShort();
1✔
585
        return items[itemIndex];
1✔
586
    }
587

588
    @NonNegative
589
    public final int readItem(@NonNegative int u2CodeIndex) {
590
        int itemIndex = readUnsignedShort(u2CodeIndex);
1✔
591
        return items[itemIndex];
1✔
592
    }
593
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc