• 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.19
/main/src/main/java/mockit/asm/methods/MethodReader.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.methods;
7

8
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.FIELDORMETH;
9
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.IINC_INSN;
10
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.IMPLVAR;
11
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.INDYMETH;
12
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.ITFMETH;
13
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.LABEL;
14
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.LABELW;
15
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.LDCW_INSN;
16
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.LDC_INSN;
17
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.LOOK_INSN;
18
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.MANA_INSN;
19
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.NOARG;
20
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.SBYTE;
21
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.SHORT;
22
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.TABL_INSN;
23
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.TYPE_INSN;
24
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.VAR;
25
import static mockit.asm.jvmConstants.JVMInstruction.InstructionType.WIDE_INSN;
26
import static mockit.asm.jvmConstants.Opcodes.IINC;
27
import static mockit.asm.jvmConstants.Opcodes.ILOAD;
28
import static mockit.asm.jvmConstants.Opcodes.ILOAD_0;
29
import static mockit.asm.jvmConstants.Opcodes.INVOKEINTERFACE;
30
import static mockit.asm.jvmConstants.Opcodes.INVOKEVIRTUAL;
31
import static mockit.asm.jvmConstants.Opcodes.ISTORE;
32
import static mockit.asm.jvmConstants.Opcodes.ISTORE_0;
33

34
import edu.umd.cs.findbugs.annotations.NonNull;
35
import edu.umd.cs.findbugs.annotations.Nullable;
36

37
import mockit.asm.AnnotatedReader;
38
import mockit.asm.annotations.AnnotationVisitor;
39
import mockit.asm.classes.ClassReader;
40
import mockit.asm.classes.ClassVisitor;
41
import mockit.asm.controlFlow.Label;
42
import mockit.asm.jvmConstants.ConstantPoolTypes;
43
import mockit.asm.jvmConstants.JVMInstruction;
44
import mockit.asm.util.MethodHandle;
45

46
import org.checkerframework.checker.index.qual.NonNegative;
47

48
@SuppressWarnings("OverlyComplexClass")
49
public final class MethodReader extends AnnotatedReader {
50
    @NonNull
51
    private final ClassReader cr;
52
    @NonNull
53
    private final ClassVisitor cv;
54

55
    @Nullable
56
    private String[] throwsClauseTypes;
57

58
    /**
59
     * The name of the method currently being parsed.
60
     */
61
    private String name;
62

63
    /**
64
     * The descriptor of the method currently being parsed.
65
     */
66
    private String desc;
67

68
    @NonNegative
69
    private int methodStartCodeIndex;
70
    @NonNegative
71
    private int bodyStartCodeIndex;
72
    @NonNegative
73
    private int parameterAnnotationsCodeIndex;
74

75
    /**
76
     * The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for
77
     * which a label is needed have a non null associated <code>Label</code> object).
78
     */
79
    private Label[] labels;
80

81
    /**
82
     * The visitor to visit the method being read.
83
     */
84
    private MethodVisitor mv;
85

86
    public MethodReader(@NonNull ClassReader cr, @NonNull ClassVisitor cv) {
87
        super(cr);
1✔
88
        this.cr = cr;
1✔
89
        this.cv = cv;
1✔
90
    }
1✔
91

92
    /**
93
     * Reads each method and constructor in the class, making the {@linkplain #cr class reader}'s
94
     * {@linkplain ClassReader#cv visitor} visit it.
95
     *
96
     * @return the offset of the first byte following the last method in the class
97
     */
98
    @NonNegative
99
    public int readMethods() {
100
        for (int methodCount = readUnsignedShort(); methodCount > 0; methodCount--) {
1✔
101
            readMethod();
1✔
102
        }
103

104
        return codeIndex;
1✔
105
    }
106

107
    private void readMethod() {
108
        readMethodDeclaration();
1✔
109
        parameterAnnotationsCodeIndex = 0;
1✔
110

111
        readAttributes();
1✔
112

113
        int currentCodeIndex = codeIndex;
1✔
114
        readMethodBody();
1✔
115
        codeIndex = currentCodeIndex;
1✔
116
    }
1✔
117

118
    private void readMethodDeclaration() {
119
        access = readUnsignedShort();
1✔
120
        name = readNonnullUTF8();
1✔
121
        desc = readNonnullUTF8();
1✔
122

123
        methodStartCodeIndex = codeIndex;
1✔
124
        bodyStartCodeIndex = 0;
1✔
125
        throwsClauseTypes = null;
1✔
126
    }
1✔
127

128
    @Nullable
129
    @Override
130
    protected Boolean readAttribute(@NonNull String attributeName) {
131
        switch (attributeName) {
1✔
132
            case "Code":
133
                bodyStartCodeIndex = codeIndex;
1✔
134
                return false;
1✔
135
            case "Exceptions":
136
                readExceptionsInThrowsClause();
1✔
137
                return true;
1✔
138
            case "RuntimeVisibleParameterAnnotations":
139
                parameterAnnotationsCodeIndex = codeIndex;
1✔
140
                return false;
1✔
141
            default:
142
                return null;
1✔
143
        }
144
    }
145

146
    private void readExceptionsInThrowsClause() {
147
        int n = readUnsignedShort();
1✔
148
        String[] typeDescs = new String[n];
1✔
149

150
        for (int i = 0; i < n; i++) {
1✔
151
            typeDescs[i] = readNonnullClass();
1✔
152
        }
153

154
        throwsClauseTypes = typeDescs;
1✔
155
    }
1✔
156

157
    private void readMethodBody() {
158
        mv = cv.visitMethod(access, name, desc, signature, throwsClauseTypes);
1✔
159

160
        if (mv == null) {
1✔
161
            return;
1✔
162
        }
163

164
        if (mv instanceof MethodWriter) {
1✔
165
            copyMethodBody();
1✔
166
            return;
1✔
167
        }
168

169
        readAnnotations(mv);
1✔
170
        readAnnotationsOnAllParameters();
1✔
171

172
        if (bodyStartCodeIndex > 0) {
1✔
173
            codeIndex = bodyStartCodeIndex;
1✔
174
            readCode();
1✔
175
        }
176

177
        mv.visitEnd();
1✔
178
    }
1✔
179

180
    /**
181
     * If the returned <code>MethodVisitor</code> is in fact a <code>MethodWriter</code>, it means there is no method
182
     * adapter between the reader and the writer. In addition, it's assumed that the writer's constant pool was copied
183
     * from this reader (mw.cw.cr == this.cr), and the signature of the method has not been changed; then, we skip all
184
     * visit events and just copy the original code of the method to the writer.
185
     */
186
    private void copyMethodBody() {
187
        // We do not copy directly the code into MethodWriter to save a byte array copy operation.
188
        // The real copy will be done in ClassWriter.toByteArray().
189
        MethodWriter mw = (MethodWriter) mv;
1✔
190
        mw.classReaderOffset = methodStartCodeIndex;
1✔
191
        mw.classReaderLength = codeIndex - methodStartCodeIndex;
1✔
192
    }
1✔
193

194
    private void readAnnotationsOnAllParameters() {
195
        if (parameterAnnotationsCodeIndex > 0) {
1✔
196
            codeIndex = parameterAnnotationsCodeIndex;
1✔
197
            int parameters = readUnsignedByte();
1✔
198

199
            for (int i = 0; i < parameters; i++) {
1✔
200
                readParameterAnnotations(i);
1✔
201
            }
202
        }
203
    }
1✔
204

205
    private void readParameterAnnotations(@NonNegative int parameterIndex) {
206
        for (int annotationCount = readUnsignedShort(); annotationCount > 0; annotationCount--) {
1✔
207
            String annotationTypeDesc = readNonnullUTF8();
1✔
208
            AnnotationVisitor av = mv.visitParameterAnnotation(parameterIndex, annotationTypeDesc);
1✔
209
            readAnnotationValues(av);
1✔
210
        }
211
    }
1✔
212

213
    private void readCode() {
214
        int maxStack = readUnsignedShort();
1✔
215
        codeIndex += 2; // skip maxLocals
1✔
216

217
        int codeLength = readInt();
1✔
218
        labels = new Label[codeLength + 2];
1✔
219

220
        // Reads the bytecode to find the labels.
221
        int codeStartIndex = codeIndex;
1✔
222
        int codeEndIndex = codeStartIndex + codeLength;
1✔
223

224
        readAllLabelsInCodeBlock(codeStartIndex, codeEndIndex);
1✔
225
        readTryCatchBlocks();
1✔
226

227
        // Reads the code attributes.
228
        int varTableCodeIndex = 0;
1✔
229
        int[] typeTable = null;
1✔
230

231
        for (int attributeCount = readUnsignedShort(); attributeCount > 0; attributeCount--) {
1✔
232
            String attrName = readNonnullUTF8();
1✔
233
            int codeOffset = readInt();
1✔
234

235
            switch (attrName) {
1✔
236
                case "LocalVariableTable":
237
                    varTableCodeIndex = codeIndex;
1✔
238
                    readLocalVariableTable();
1✔
239
                    break;
1✔
240
                case "LocalVariableTypeTable":
241
                    typeTable = readLocalVariableTypeTable();
1✔
242
                    break;
1✔
243
                case "LineNumberTable":
244
                    readLineNumberTable();
1✔
245
                    break;
1✔
246
                default:
247
                    codeIndex += codeOffset;
1✔
248
            }
249
        }
250

251
        readBytecodeInstructionsInCodeBlock(codeStartIndex, codeEndIndex);
1✔
252
        visitEndLabel(codeLength);
1✔
253
        readLocalVariableTables(varTableCodeIndex, typeTable);
1✔
254
        mv.visitMaxStack(maxStack);
1✔
255
    }
1✔
256

257
    private void readAllLabelsInCodeBlock(@NonNegative int codeStart, @NonNegative int codeEnd) {
258
        getOrCreateLabel(codeEnd - codeStart + 1);
1✔
259

260
        while (codeIndex < codeEnd) {
1✔
261
            int offset = codeIndex - codeStart;
1✔
262
            readLabelForInstructionIfAny(offset);
1✔
263
        }
1✔
264
    }
1✔
265

266
    @NonNull
267
    private Label getOrCreateLabel(@NonNegative int offset) {
268
        Label label = labels[offset];
1✔
269

270
        if (label == null) {
1✔
271
            label = new Label();
1✔
272
            labels[offset] = label;
1✔
273
        }
274

275
        return label;
1✔
276
    }
277

278
    private void readLabelForInstructionIfAny(@NonNegative int offset) {
279
        int opcode = readUnsignedByte();
1✔
280
        byte instructionType = JVMInstruction.TYPE[opcode];
1✔
281
        boolean tablInsn = instructionType == TABL_INSN;
1✔
282

283
        if (tablInsn || instructionType == LOOK_INSN) {
1✔
284
            readLabelsForSwitchInstruction(offset, tablInsn);
1✔
285
        } else {
286
            readLabelsForNonSwitchInstruction(offset, instructionType);
1✔
287
        }
288
    }
1✔
289

290
    private void readLabelsForSwitchInstruction(@NonNegative int offset, boolean tableNotLookup) {
291
        readSwitchDefaultLabel(offset);
1✔
292

293
        int caseCount;
294

295
        if (tableNotLookup) {
1✔
296
            int min = readInt();
1✔
297
            int max = readInt();
1✔
298
            caseCount = max - min + 1;
1✔
299
        } else {
1✔
300
            caseCount = readInt();
1✔
301
        }
302

303
        while (caseCount > 0) {
1✔
304
            if (!tableNotLookup) {
1✔
305
                codeIndex += 4;
1✔
306
            }
307

308
            int caseOffset = offset + readInt();
1✔
309
            getOrCreateLabel(caseOffset);
1✔
310
            caseCount--;
1✔
311
        }
1✔
312
    }
1✔
313

314
    @NonNull
315
    private Label readSwitchDefaultLabel(@NonNegative int offset) {
316
        codeIndex += 3 - (offset & 3); // skips 0 to 3 padding bytes
1✔
317

318
        int defaultLabelOffset = readInt();
1✔
319
        return getOrCreateLabel(offset + defaultLabelOffset);
1✔
320
    }
321

322
    @SuppressWarnings("OverlyLongMethod")
323
    private void readLabelsForNonSwitchInstruction(@NonNegative int offset, byte instructionType) {
324
        int codeIndexSize = 0;
1✔
325

326
        // noinspection SwitchStatementWithoutDefaultBranch
327
        switch (instructionType) {
1!
328
            case NOARG:
329
            case IMPLVAR:
330
                return;
1✔
331
            case LABEL:
332
                int labelOffset = offset + readShort();
1✔
333
                getOrCreateLabel(labelOffset);
1✔
334
                return;
1✔
335
            case LABELW:
336
                int labelOffsetW = offset + readInt();
×
337
                getOrCreateLabel(labelOffsetW);
×
338
                return;
×
339
            case WIDE_INSN:
340
                int opcode = readUnsignedByte();
×
341
                codeIndexSize = opcode == IINC ? 4 : 2;
×
342
                break;
×
343
            case VAR:
344
            case SBYTE:
345
            case LDC_INSN:
346
                codeIndexSize = 1;
1✔
347
                break;
1✔
348
            case SHORT:
349
            case LDCW_INSN:
350
            case TYPE_INSN:
351
            case FIELDORMETH:
352
            case IINC_INSN:
353
                codeIndexSize = 2;
1✔
354
                break;
1✔
355
            case ITFMETH:
356
            case INDYMETH:
357
                codeIndexSize = 4;
1✔
358
                break;
1✔
359
            case MANA_INSN:
360
                codeIndexSize = 3;
×
361
        }
362

363
        codeIndex += codeIndexSize;
1✔
364
    }
1✔
365

366
    /**
367
     * Reads the try catch entries to find the labels, and also visits them.
368
     */
369
    private void readTryCatchBlocks() {
370
        for (int blockCount = readUnsignedShort(); blockCount > 0; blockCount--) {
1✔
371
            Label start = getOrCreateLabel(readUnsignedShort());
1✔
372
            Label end = getOrCreateLabel(readUnsignedShort());
1✔
373
            Label handler = getOrCreateLabel(readUnsignedShort());
1✔
374
            String type = readUTF8(readItem());
1✔
375

376
            mv.visitTryCatchBlock(start, end, handler, type);
1✔
377
        }
378
    }
1✔
379

380
    private void readLocalVariableTable() {
381
        for (int localVarCount = readUnsignedShort(); localVarCount > 0; localVarCount--) {
1✔
382
            int labelOffset = readUnsignedShort();
1✔
383
            getOrCreateDebugLabel(labelOffset);
1✔
384

385
            labelOffset += readUnsignedShort();
1✔
386
            getOrCreateDebugLabel(labelOffset);
1✔
387

388
            codeIndex += 6;
1✔
389
        }
390
    }
1✔
391

392
    @NonNull
393
    private Label getOrCreateDebugLabel(@NonNegative int offset) {
394
        Label label = labels[offset];
1✔
395

396
        if (label == null) {
1✔
397
            label = new Label();
1✔
398
            label.markAsDebug();
1✔
399
            labels[offset] = label;
1✔
400
        }
401

402
        return label;
1✔
403
    }
404

405
    @NonNull
406
    private int[] readLocalVariableTypeTable() {
407
        int typeTableSize = 3 * readUnsignedShort();
1✔
408
        int[] typeTable = new int[typeTableSize];
1✔
409

410
        while (typeTableSize > 0) {
1✔
411
            int startIndex = readUnsignedShort();
1✔
412
            int signatureCodeIndex = codeIndex + 4;
1✔
413
            codeIndex += 6;
1✔
414
            int varIndex = readUnsignedShort();
1✔
415

416
            typeTableSize--;
1✔
417
            typeTable[typeTableSize] = signatureCodeIndex;
1✔
418
            typeTableSize--;
1✔
419
            typeTable[typeTableSize] = varIndex;
1✔
420
            typeTableSize--;
1✔
421
            typeTable[typeTableSize] = startIndex;
1✔
422
        }
1✔
423

424
        return typeTable;
1✔
425
    }
426

427
    private void readLineNumberTable() {
428
        for (int lineCount = readUnsignedShort(); lineCount > 0; lineCount--) {
1✔
429
            int labelOffset = readUnsignedShort();
1✔
430
            Label debugLabel = getOrCreateDebugLabel(labelOffset);
1✔
431
            debugLabel.line = readUnsignedShort();
1✔
432
        }
433
    }
1✔
434

435
    @SuppressWarnings({ "OverlyComplexMethod", "OverlyLongMethod" })
436
    private void readBytecodeInstructionsInCodeBlock(@NonNegative int codeStartIndex, @NonNegative int codeEndIndex) {
437
        codeIndex = codeStartIndex;
1✔
438

439
        while (codeIndex < codeEndIndex) {
1✔
440
            int offset = codeIndex - codeStartIndex;
1✔
441
            visitLabelAndLineNumber(offset);
1✔
442

443
            int opcode = readUnsignedByte();
1✔
444

445
            // noinspection SwitchStatementWithoutDefaultBranch
446
            switch (JVMInstruction.TYPE[opcode]) {
1!
447
                case NOARG:
448
                    mv.visitInsn(opcode);
1✔
449
                    break;
1✔
450
                case VAR:
451
                    readVariableAccessInstruction(opcode);
1✔
452
                    break;
1✔
453
                case IMPLVAR:
454
                    readInstructionWithImplicitVariable(opcode);
1✔
455
                    break;
1✔
456
                case TYPE_INSN:
457
                    readTypeInsn(opcode);
1✔
458
                    break;
1✔
459
                case LABEL:
460
                    readJump(opcode, offset);
1✔
461
                    break;
1✔
462
                case LABELW:
463
                    readWideJump(opcode, offset);
×
464
                    break;
×
465
                case LDC_INSN:
466
                    readLDC();
1✔
467
                    break;
1✔
468
                case LDCW_INSN:
469
                    readLDCW();
1✔
470
                    break;
1✔
471
                case IINC_INSN:
472
                    readIInc();
1✔
473
                    break;
1✔
474
                case SBYTE:
475
                    readInstructionTakingASignedByte(opcode);
1✔
476
                    break;
1✔
477
                case SHORT:
478
                    readInstructionTakingASignedShort(opcode);
1✔
479
                    break;
1✔
480
                case TABL_INSN:
481
                    readSwitchInstruction(offset, true);
1✔
482
                    break;
1✔
483
                case LOOK_INSN:
484
                    readSwitchInstruction(offset, false);
1✔
485
                    break;
1✔
486
                case MANA_INSN:
487
                    readMultiANewArray();
×
488
                    break;
×
489
                case WIDE_INSN:
490
                    readWideInstruction();
×
491
                    break;
×
492
                case FIELDORMETH:
493
                case ITFMETH:
494
                    readFieldOrInvokeInstruction(opcode);
1✔
495
                    break;
1✔
496
                case INDYMETH:
497
                    readInvokeDynamicInstruction();
1✔
498
                    break;
499
            }
500
        }
1✔
501
    }
1✔
502

503
    private void visitLabelAndLineNumber(@NonNegative int offset) {
504
        Label label = labels[offset];
1✔
505

506
        if (label != null) {
1✔
507
            mv.visitLabel(label);
1✔
508

509
            int lineNumber = label.line;
1✔
510

511
            if (lineNumber > 0) {
1✔
512
                mv.visitLineNumber(lineNumber, label);
1✔
513
            }
514
        }
515
    }
1✔
516

517
    private void readVariableAccessInstruction(int opcode) {
518
        int varIndex = readUnsignedByte();
1✔
519
        mv.visitVarInsn(opcode, varIndex);
1✔
520
    }
1✔
521

522
    private void readInstructionWithImplicitVariable(int opcode) {
523
        int opcodeBase;
524

525
        if (opcode > ISTORE) {
1✔
526
            opcode -= ISTORE_0;
1✔
527
            opcodeBase = ISTORE;
1✔
528
        } else {
529
            opcode -= ILOAD_0;
1✔
530
            opcodeBase = ILOAD;
1✔
531
        }
532

533
        int localVarOpcode = opcodeBase + (opcode >> 2);
1✔
534
        int varIndex = opcode & 3;
1✔
535

536
        mv.visitVarInsn(localVarOpcode, varIndex);
1✔
537
    }
1✔
538

539
    private void readTypeInsn(int opcode) {
540
        String typeDesc = readNonnullClass();
1✔
541
        mv.visitTypeInsn(opcode, typeDesc);
1✔
542
    }
1✔
543

544
    private void readJump(int opcode, @NonNegative int offset) {
545
        short targetIndex = readShort();
1✔
546
        Label targetLabel = labels[offset + targetIndex];
1✔
547
        mv.visitJumpInsn(opcode, targetLabel);
1✔
548
    }
1✔
549

550
    private void readWideJump(int opcode, @NonNegative int offset) {
551
        int targetIndex = readInt();
×
552
        Label targetLabel = labels[offset + targetIndex];
×
553
        mv.visitJumpInsn(opcode - 33, targetLabel);
×
554
    }
×
555

556
    private void readLDC() {
557
        int constIndex = readUnsignedByte();
1✔
558
        Object cst = readConst(constIndex);
1✔
559
        mv.visitLdcInsn(cst);
1✔
560
    }
1✔
561

562
    private void readLDCW() {
563
        Object cst = readConstItem();
1✔
564
        mv.visitLdcInsn(cst);
1✔
565
    }
1✔
566

567
    private void readIInc() {
568
        int varIndex = readUnsignedByte();
1✔
569
        int increment = readSignedByte();
1✔
570
        mv.visitIincInsn(varIndex, increment);
1✔
571
    }
1✔
572

573
    private void readInstructionTakingASignedByte(int opcode) {
574
        int operand = readSignedByte();
1✔
575
        mv.visitIntInsn(opcode, operand);
1✔
576
    }
1✔
577

578
    private void readInstructionTakingASignedShort(int opcode) {
579
        int operand = readShort();
1✔
580
        mv.visitIntInsn(opcode, operand);
1✔
581
    }
1✔
582

583
    private void readSwitchInstruction(@NonNegative int offset, boolean tableNotLookup) {
584
        Label dfltLabel = readSwitchDefaultLabel(offset);
1✔
585
        int min;
586
        int max;
587
        int caseCount;
588
        int[] keys;
589

590
        if (tableNotLookup) {
1✔
591
            min = readInt();
1✔
592
            max = readInt();
1✔
593
            caseCount = max - min + 1;
1✔
594
            keys = null;
1✔
595
        } else {
596
            min = max = 0;
1✔
597
            caseCount = readInt();
1✔
598
            keys = new int[caseCount];
1✔
599
        }
600

601
        Label[] handlerLabels = readSwitchCaseLabels(offset, caseCount, keys);
1✔
602

603
        if (tableNotLookup) {
1✔
604
            mv.visitTableSwitchInsn(min, max, dfltLabel, handlerLabels);
1✔
605
        } else {
606
            mv.visitLookupSwitchInsn(dfltLabel, keys, handlerLabels);
1✔
607
        }
608
    }
1✔
609

610
    @NonNull
611
    private Label[] readSwitchCaseLabels(@NonNegative int offset, @NonNegative int caseCount, @Nullable int[] keys) {
612
        Label[] caseLabels = new Label[caseCount];
1✔
613

614
        for (int i = 0; i < caseCount; i++) {
1✔
615
            if (keys != null) {
1✔
616
                keys[i] = readInt();
1✔
617
            }
618

619
            int labelOffset = offset + readInt();
1✔
620
            caseLabels[i] = labels[labelOffset];
1✔
621
        }
622

623
        return caseLabels;
1✔
624
    }
625

626
    private void readMultiANewArray() {
627
        String arrayTypeDesc = readNonnullClass();
×
628
        int dims = readUnsignedByte();
×
629
        mv.visitMultiANewArrayInsn(arrayTypeDesc, dims);
×
630
    }
×
631

632
    private void readWideInstruction() {
633
        int opcode = readUnsignedByte();
×
634
        int varIndex = readUnsignedShort();
×
635

636
        if (opcode == IINC) {
×
637
            int increment = readShort();
×
638
            mv.visitIincInsn(varIndex, increment);
×
639
        } else {
×
640
            mv.visitVarInsn(opcode, varIndex);
×
641
            codeIndex += 2;
×
642
        }
643
    }
×
644

645
    private void readFieldOrInvokeInstruction(int opcode) {
646
        int ownerCodeIndex = readItem();
1✔
647
        String owner = readNonnullClass(ownerCodeIndex);
1✔
648
        int nameCodeIndex = readItem(ownerCodeIndex + 2);
1✔
649
        String memberName = readNonnullUTF8(nameCodeIndex);
1✔
650
        String memberDesc = readNonnullUTF8(nameCodeIndex + 2);
1✔
651

652
        if (opcode < INVOKEVIRTUAL) {
1✔
653
            mv.visitFieldInsn(opcode, owner, memberName, memberDesc);
1✔
654
        } else {
655
            boolean itf = code[ownerCodeIndex - 1] == ConstantPoolTypes.IMETHOD_REF;
1✔
656
            mv.visitMethodInsn(opcode, owner, memberName, memberDesc, itf);
1✔
657

658
            if (opcode == INVOKEINTERFACE) {
1✔
659
                codeIndex += 2;
1✔
660
            }
661
        }
662
    }
1✔
663

664
    private void readInvokeDynamicInstruction() {
665
        int cpIndex = readItem();
1✔
666
        int bsmStartIndex = readUnsignedShort(cpIndex);
1✔
667
        int nameCodeIndex = readItem(cpIndex + 2);
1✔
668

669
        String bsmName = readNonnullUTF8(nameCodeIndex);
1✔
670
        String bsmDesc = readNonnullUTF8(nameCodeIndex + 2);
1✔
671

672
        int bsmCodeIndex = cr.getBSMCodeIndex(bsmStartIndex);
1✔
673
        MethodHandle bsmHandle = readMethodHandleItem(bsmCodeIndex);
1✔
674
        int bsmArgCount = readUnsignedShort(bsmCodeIndex + 2);
1✔
675
        bsmCodeIndex += 4;
1✔
676
        Object[] bsmArgs = new Object[bsmArgCount];
1✔
677

678
        for (int i = 0; i < bsmArgCount; i++) {
1✔
679
            bsmArgs[i] = readConstItem(bsmCodeIndex);
1✔
680
            bsmCodeIndex += 2;
1✔
681
        }
682

683
        mv.visitInvokeDynamicInsn(bsmName, bsmDesc, bsmHandle, bsmArgs);
1✔
684
        codeIndex += 2;
1✔
685
    }
1✔
686

687
    private void visitEndLabel(@NonNegative int codeLength) {
688
        Label label = labels[codeLength];
1✔
689

690
        if (label != null) {
1✔
691
            mv.visitLabel(label);
1✔
692
        }
693
    }
1✔
694

695
    private void readLocalVariableTables(@NonNegative int varTableCodeIndex, @Nullable int[] typeTable) {
696
        if (varTableCodeIndex > 0) {
1✔
697
            codeIndex = varTableCodeIndex;
1✔
698

699
            for (int localVarCount = readUnsignedShort(); localVarCount > 0; localVarCount--) {
1✔
700
                int start = readUnsignedShort();
1✔
701
                int length = readUnsignedShort();
1✔
702
                String varName = readNonnullUTF8();
1✔
703
                String varDesc = readNonnullUTF8();
1✔
704
                int index = readUnsignedShort();
1✔
705
                String varSignature = typeTable == null ? null : getLocalVariableSignature(typeTable, start, index);
1✔
706

707
                mv.visitLocalVariable(varName, varDesc, varSignature, labels[start], labels[start + length], index);
1✔
708
            }
709
        }
710
    }
1✔
711

712
    @Nullable
713
    private String getLocalVariableSignature(@NonNull int[] typeTable, @NonNegative int start, @NonNegative int index) {
714
        for (int i = 0, n = typeTable.length; i < n; i += 3) {
1✔
715
            if (typeTable[i] == start && typeTable[i + 1] == index) {
1✔
716
                return readNonnullUTF8(typeTable[i + 2]);
1✔
717
            }
718
        }
719

720
        return null;
1✔
721
    }
722
}
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