• 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

82.64
/main/src/main/java/mockit/asm/controlFlow/Frame.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.controlFlow;
7

8
import static mockit.asm.controlFlow.FrameTypeMask.ARRAY_OF;
9
import static mockit.asm.controlFlow.FrameTypeMask.BASE;
10
import static mockit.asm.controlFlow.FrameTypeMask.BASE_KIND;
11
import static mockit.asm.controlFlow.FrameTypeMask.BASE_VALUE;
12
import static mockit.asm.controlFlow.FrameTypeMask.BOOLEAN;
13
import static mockit.asm.controlFlow.FrameTypeMask.BYTE;
14
import static mockit.asm.controlFlow.FrameTypeMask.CHAR;
15
import static mockit.asm.controlFlow.FrameTypeMask.DIM;
16
import static mockit.asm.controlFlow.FrameTypeMask.DOUBLE;
17
import static mockit.asm.controlFlow.FrameTypeMask.ELEMENT_OF;
18
import static mockit.asm.controlFlow.FrameTypeMask.FLOAT;
19
import static mockit.asm.controlFlow.FrameTypeMask.INTEGER;
20
import static mockit.asm.controlFlow.FrameTypeMask.KIND;
21
import static mockit.asm.controlFlow.FrameTypeMask.LOCAL;
22
import static mockit.asm.controlFlow.FrameTypeMask.LONG;
23
import static mockit.asm.controlFlow.FrameTypeMask.NULL;
24
import static mockit.asm.controlFlow.FrameTypeMask.OBJECT;
25
import static mockit.asm.controlFlow.FrameTypeMask.SHORT;
26
import static mockit.asm.controlFlow.FrameTypeMask.STACK;
27
import static mockit.asm.controlFlow.FrameTypeMask.TOP;
28
import static mockit.asm.controlFlow.FrameTypeMask.TOP_IF_LONG_OR_DOUBLE;
29
import static mockit.asm.controlFlow.FrameTypeMask.UNINITIALIZED;
30
import static mockit.asm.controlFlow.FrameTypeMask.UNINITIALIZED_THIS;
31
import static mockit.asm.controlFlow.FrameTypeMask.VALUE;
32
import static mockit.asm.jvmConstants.Opcodes.*;
33

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

37
import mockit.asm.constantPool.ConstantPoolGeneration;
38
import mockit.asm.constantPool.DynamicItem;
39
import mockit.asm.constantPool.Item;
40
import mockit.asm.constantPool.StringItem;
41
import mockit.asm.constantPool.TypeOrMemberItem;
42
import mockit.asm.jvmConstants.Access;
43
import mockit.asm.jvmConstants.ArrayElementType;
44
import mockit.asm.jvmConstants.ConstantPoolTypes;
45
import mockit.asm.types.ArrayType;
46
import mockit.asm.types.JavaType;
47
import mockit.asm.types.PrimitiveType;
48

49
import org.checkerframework.checker.index.qual.NonNegative;
50

51
/**
52
 * Information about the input and output stack map frames of a basic block.
53
 * <p>
54
 * Frames are computed in a two steps process: during the visit of each instruction, the state of the frame at the end
55
 * of current basic block is updated by simulating the action of the instruction on the previous state of this so called
56
 * "output frame". In visitMaxStack, a fix point algorithm is used to compute the "input frame" of each basic block,
57
 * i.e. the stack map frame at the beginning of the basic block, starting from the input frame of the first basic block
58
 * (which is computed from the method descriptor), and by using the previously computed output frames to compute the
59
 * input state of the other blocks.
60
 * <p>
61
 * All output and input frames are stored as arrays of integers. Reference and array types are represented by an index
62
 * into a type table (which is not the same as the constant pool of the class, in order to avoid adding unnecessary
63
 * constants in the pool - not all computed frames will end up being stored in the stack map table). This allows very
64
 * fast type comparisons.
65
 * <p>
66
 * Output stack map frames are computed relatively to the input frame of the basic block, which is not yet known when
67
 * output frames are computed. It is therefore necessary to be able to represent abstract types such as "the type at
68
 * position x in the input frame locals" or "the type at position x from the top of the input frame stack" or even "the
69
 * type at position x in the input frame, with y more (or less) array dimensions". This explains the rather complicated
70
 * type format used in output frames.
71
 * <p>
72
 * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a signed number of array dimensions (from -8
73
 * to 7). KIND is either BASE, LOCAL or STACK. BASE is used for types that are not relative to the input frame. LOCAL is
74
 * used for types that are relative to the input local variable types. STACK is used for types that are relative to the
75
 * input stack types. VALUE depends on KIND. For LOCAL types, it is an index in the input local variable types. For
76
 * STACK types, it is a position relatively to the top of input frame stack. For BASE types, it is either one of the
77
 * constants defined below, or for OBJECT and UNINITIALIZED types, a tag and an index in the type table.
78
 * <p>
79
 * Output frames can contain types of any kind and with a positive or negative dimension (and even unassigned types,
80
 * represented by 0 - which does not correspond to any valid type value). Input frames can only contain BASE types of
81
 * positive or null dimension. In all cases the type table contains only internal type names (array type descriptors are
82
 * forbidden - dimensions must be represented through the DIM field).
83
 * <p>
84
 * The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + TOP), for local variable
85
 * types as well as in the operand stack. This is necessary to be able to simulate DUPx_y instructions, whose effect
86
 * would be dependent on the actual type values if types were always represented by a single slot in the stack (and this
87
 * is not possible, since actual type values are not always known - cf LOCAL and STACK type kinds).
88
 */
89
public final class Frame {
90
    private static final int[] EMPTY_INPUT_STACK = {};
1✔
91

92
    @NonNull
93
    private final ConstantPoolGeneration cp;
94

95
    /**
96
     * The label (i.e. basic block) to which these input and output stack map frames correspond.
97
     */
98
    @NonNull
99
    final Label owner;
100

101
    /**
102
     * The input stack map frame locals.
103
     */
104
    int[] inputLocals;
105

106
    /**
107
     * The input stack map frame stack.
108
     */
109
    int[] inputStack;
110

111
    /**
112
     * The output stack map frame locals.
113
     */
114
    @Nullable
115
    private int[] outputLocals;
116

117
    /**
118
     * The output stack map frame stack.
119
     */
120
    private int[] outputStack;
121

122
    /**
123
     * Relative size of the output stack. The exact semantics of this field depends on the algorithm that is used.
124
     * <p>
125
     * When only the maximum stack size is computed, this field is the size of the output stack relatively to the top of
126
     * the input stack.
127
     * <p>
128
     * When the stack map frames are completely computed, this field is the actual number of types in
129
     * {@link #outputStack}.
130
     */
131
    @NonNegative
132
    private int outputStackTop;
133

134
    /**
135
     * Number of types that are initialized in the basic block.
136
     *
137
     * @see #initializations
138
     */
139
    private int initializationCount;
140

141
    /**
142
     * The types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED or
143
     * UNINITIALIZED_THIS type must replace <em>every occurrence</em> of this type in the local variables and in the
144
     * operand stack. This cannot be done during the first phase of the algorithm since, during this phase, the local
145
     * variables and the operand stack are not completely computed. It is therefore necessary to store the types on
146
     * which constructors are invoked in the basic block, in order to do this replacement during the second phase of the
147
     * algorithm, where the frames are fully computed. Note that this array can contain types that are relative to input
148
     * locals or to the input stack.
149
     */
150
    private int[] initializations;
151

152
    Frame(@NonNull ConstantPoolGeneration cp, @NonNull Label owner) {
1✔
153
        this.cp = cp;
1✔
154
        this.owner = owner;
1✔
155
    }
1✔
156

157
    /**
158
     * Initializes the input frame of the first basic block from the method descriptor.
159
     *
160
     * @param access
161
     *            the access flags of the method to which this label belongs.
162
     * @param args
163
     *            the formal parameter types of this method.
164
     * @param maxLocals
165
     *            the maximum number of local variables of this method.
166
     */
167
    void initInputFrame(@NonNull String classDesc, int access, @NonNull JavaType[] args, @NonNegative int maxLocals) {
168
        inputLocals = new int[maxLocals];
1✔
169
        inputStack = EMPTY_INPUT_STACK;
1✔
170

171
        int localIndex = initializeThisParameterIfApplicable(classDesc, access);
1✔
172
        localIndex = initializeFormalParameterTypes(localIndex, args);
1✔
173

174
        while (localIndex < maxLocals) {
1✔
175
            inputLocals[localIndex] = TOP;
1✔
176
            localIndex++;
1✔
177
        }
178
    }
1✔
179

180
    @NonNegative
181
    private int initializeThisParameterIfApplicable(@NonNull String classDesc, int access) {
182
        if ((access & Access.STATIC) == 0) {
1✔
183
            inputLocals[0] = Access.isConstructor(access) ? UNINITIALIZED_THIS : OBJECT | cp.addNormalType(classDesc);
1✔
184
            return 1;
1✔
185
        }
186

187
        return 0;
1✔
188
    }
189

190
    @NonNegative
191
    private int initializeFormalParameterTypes(@NonNegative int localIndex, @NonNull JavaType[] args) {
192
        for (JavaType arg : args) {
1✔
193
            int typeEncoding = getTypeEncoding(arg.getDescriptor());
1✔
194
            inputLocals[localIndex] = typeEncoding;
1✔
195
            localIndex++;
1✔
196

197
            if (typeEncoding == LONG || typeEncoding == DOUBLE) {
1✔
198
                inputLocals[localIndex] = TOP;
1✔
199
                localIndex++;
1✔
200
            }
201
        }
202

203
        return localIndex;
1✔
204
    }
205

206
    /**
207
     * Returns the {@linkplain FrameTypeMask int encoding} of the given type.
208
     *
209
     * @param typeDesc
210
     *            a type descriptor
211
     *
212
     * @return the int encoding of the given type
213
     */
214
    @NonNegative
215
    private int getTypeEncoding(@NonNull String typeDesc) {
216
        int index = typeDesc.charAt(0) == '(' ? typeDesc.indexOf(')') + 1 : 0;
1✔
217

218
        switch (typeDesc.charAt(index)) {
1!
219
            case 'V':
220
                return 0;
1✔
221
            case 'Z':
222
            case 'C':
223
            case 'B':
224
            case 'S':
225
            case 'I':
226
                return INTEGER;
1✔
227
            case 'F':
228
                return FLOAT;
1✔
229
            case 'J':
230
                return LONG;
1✔
231
            case 'D':
232
                return DOUBLE;
1✔
233
            case 'L':
234
                return getObjectTypeEncoding(typeDesc, index);
1✔
235
            case '[':
236
                return getArrayTypeEncoding(typeDesc, index);
1✔
237
            default:
238
                throw new IllegalArgumentException("Invalid type descriptor: " + typeDesc);
×
239
        }
240
    }
241

242
    @NonNegative
243
    private int getObjectTypeEncoding(@NonNull String typeDesc, @NonNegative int index) {
244
        // Stores the internal name, not the descriptor!
245
        String t = typeDesc.substring(index + 1, typeDesc.length() - 1);
1✔
246
        return OBJECT | cp.addNormalType(t);
1✔
247
    }
248

249
    @NonNegative
250
    private int getArrayTypeEncoding(@NonNull String typeDesc, @NonNegative int index) {
251
        int dims = getNumberOfDimensions(typeDesc, index);
1✔
252
        int data = getArrayElementTypeEncoding(typeDesc, index + dims);
1✔
253
        return dims << 28 | data;
1✔
254
    }
255

256
    @NonNegative
257
    private static int getNumberOfDimensions(@NonNull String typeDesc, @NonNegative int index) {
258
        int dims = 1;
1✔
259

260
        while (typeDesc.charAt(index + dims) == '[') {
1✔
261
            dims++;
1✔
262
        }
263

264
        return dims;
1✔
265
    }
266

267
    @NonNegative
268
    @SuppressWarnings("OverlyComplexMethod")
269
    private int getArrayElementTypeEncoding(@NonNull String typeDesc, @NonNegative int index) {
270
        switch (typeDesc.charAt(index)) {
1!
271
            case 'Z':
272
                return BOOLEAN;
1✔
273
            case 'C':
274
                return CHAR;
1✔
275
            case 'B':
276
                return BYTE;
1✔
277
            case 'S':
278
                return SHORT;
1✔
279
            case 'I':
280
                return INTEGER;
1✔
281
            case 'F':
282
                return FLOAT;
1✔
283
            case 'J':
284
                return LONG;
1✔
285
            case 'D':
286
                return DOUBLE;
1✔
287
            case 'L':
288
                return getObjectTypeEncoding(typeDesc, index);
1✔
289
            default:
290
                throw new IllegalArgumentException("Invalid type descriptor: " + typeDesc);
×
291
        }
292
    }
293

294
    /**
295
     * Simulates the action of a IINC instruction on the output stack frame.
296
     */
297
    void executeIINC(@NonNegative int varIndex) {
298
        set(varIndex, INTEGER);
1✔
299
    }
1✔
300

301
    /**
302
     * Sets the output frame local variable type at the given index.
303
     *
304
     * @param local
305
     *            the index of the local that must be set
306
     * @param type
307
     *            the value of the local that must be set
308
     */
309
    private void set(@NonNegative int local, int type) {
310
        // Creates and/or resizes the output local variables array if necessary.
311
        if (outputLocals == null) {
1✔
312
            outputLocals = new int[10];
1✔
313
        }
314

315
        int n = outputLocals.length;
1✔
316

317
        if (local >= n) {
1✔
318
            int[] t = new int[Math.max(local + 1, 2 * n)];
1✔
319
            System.arraycopy(outputLocals, 0, t, 0, n);
1✔
320
            outputLocals = t;
1✔
321
        }
322

323
        // Sets the local variable.
324
        outputLocals[local] = type;
1✔
325
    }
1✔
326

327
    /**
328
     * Simulates the action of a BIPUSH, SIPUSH, or NEWARRAY instruction on the output stack frame.
329
     *
330
     * @param opcode
331
     *            the opcode of the instruction
332
     * @param operand
333
     *            the operand of the instruction, if any
334
     */
335
    void executeINT(@NonNegative int opcode, int operand) {
336
        if (opcode == NEWARRAY) {
1✔
337
            executeNewArray(operand);
1✔
338
        } else {
339
            push(INTEGER);
1✔
340
        }
341
    }
1✔
342

343
    private void executeNewArray(@NonNegative int arrayElementType) {
344
        pop();
1✔
345

346
        // noinspection SwitchStatementWithoutDefaultBranch
347
        switch (arrayElementType) {
1!
348
            case ArrayElementType.BOOLEAN:
349
                push(ARRAY_OF | BOOLEAN);
1✔
350
                break;
1✔
351
            case ArrayElementType.CHAR:
352
                push(ARRAY_OF | CHAR);
1✔
353
                break;
1✔
354
            case ArrayElementType.BYTE:
355
                push(ARRAY_OF | BYTE);
1✔
356
                break;
1✔
357
            case ArrayElementType.SHORT:
358
                push(ARRAY_OF | SHORT);
1✔
359
                break;
1✔
360
            case ArrayElementType.INT:
361
                push(ARRAY_OF | INTEGER);
1✔
362
                break;
1✔
363
            case ArrayElementType.FLOAT:
364
                push(ARRAY_OF | FLOAT);
×
365
                break;
×
366
            case ArrayElementType.DOUBLE:
367
                push(ARRAY_OF | DOUBLE);
×
368
                break;
×
369
            case ArrayElementType.LONG:
370
                push(ARRAY_OF | LONG);
1✔
371
        }
372
    }
1✔
373

374
    /**
375
     * Pushes a new type onto the output frame stack.
376
     */
377
    private void push(int type) {
378
        // Creates and/or resizes the output stack array if necessary.
379
        if (outputStack == null) {
1✔
380
            outputStack = new int[10];
1✔
381
        }
382

383
        int n = outputStack.length;
1✔
384

385
        if (outputStackTop >= n) {
1✔
386
            int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
1✔
387
            System.arraycopy(outputStack, 0, t, 0, n);
1✔
388
            outputStack = t;
1✔
389
        }
390

391
        // Pushes the type on the output stack.
392
        outputStack[outputStackTop++] = type;
1✔
393

394
        owner.updateOutputStackMaxHeight(outputStackTop);
1✔
395
    }
1✔
396

397
    /**
398
     * Pops a type from the output frame stack and returns its value.
399
     */
400
    private int pop() {
401
        if (outputStackTop > 0) {
1✔
402
            return outputStack[--outputStackTop];
1✔
403
        }
404

405
        // If the output frame stack is empty, pops from the input stack.
406
        return STACK | -owner.decrementInputStackTop();
1✔
407
    }
408

409
    /**
410
     * Simulates the action of a LOOKUPSWITCH or TABLESWITCH instruction on the output stack frame.
411
     */
412
    void executeSWITCH() {
413
        pop(1);
1✔
414
    }
1✔
415

416
    /**
417
     * Pops the given number of types from the output frame stack.
418
     *
419
     * @param elements
420
     *            the number of types that must be popped.
421
     */
422
    private void pop(@NonNegative int elements) {
423
        if (outputStackTop >= elements) {
1✔
424
            outputStackTop -= elements;
1✔
425
        } else {
426
            // If the number of elements to be popped is greater than the number of elements in the output stack, clear
427
            // it,
428
            // and pops the remaining elements from the input stack.
429
            owner.decrementInputStackTop(elements - outputStackTop);
1✔
430
            outputStackTop = 0;
1✔
431
        }
432
    }
1✔
433

434
    /**
435
     * Pops a type from the output frame stack.
436
     *
437
     * @param desc
438
     *            the descriptor of the type to be popped. Can also be a method descriptor (in this case this method
439
     *            pops the types corresponding to the method arguments).
440
     */
441
    private void pop(@NonNull String desc) {
442
        char c = desc.charAt(0);
1✔
443

444
        if (c == '(') {
1✔
445
            int elements = (JavaType.getArgumentsAndReturnSizes(desc) >> 2) - 1;
1✔
446
            pop(elements);
1✔
447
        } else if (c == 'J' || c == 'D') {
1!
448
            pop(2);
1✔
449
        } else {
450
            pop(1);
1✔
451
        }
452
    }
1✔
453

454
    /**
455
     * Adds a new type to the list of types on which a constructor is invoked in the basic block.
456
     *
457
     * @param var
458
     *            a type on a which a constructor is invoked
459
     */
460
    private void init(int var) {
461
        // Creates and/or resizes the initializations array if necessary.
462
        if (initializations == null) {
1✔
463
            initializations = new int[2];
1✔
464
        }
465

466
        int n = initializations.length;
1✔
467

468
        if (initializationCount >= n) {
1✔
469
            int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
1✔
470
            System.arraycopy(initializations, 0, t, 0, n);
1✔
471
            initializations = t;
1✔
472
        }
473

474
        // Stores the type to be initialized.
475
        initializations[initializationCount++] = var;
1✔
476
    }
1✔
477

478
    /**
479
     * Replaces the given type with the appropriate type if it is one of the types on which a constructor is invoked in
480
     * the basic block.
481
     *
482
     * @return the given type or, if <code>type</code> is one of the types on which a constructor is invoked in the
483
     *         basic block, the type corresponding to this constructor
484
     */
485
    @NonNegative
486
    private int init(@NonNull String classDesc, @NonNegative int type) {
487
        int s;
488

489
        if (type == UNINITIALIZED_THIS) {
1✔
490
            s = OBJECT | cp.addNormalType(classDesc);
1✔
491
        } else if ((type & (DIM | BASE_KIND)) == UNINITIALIZED) {
1✔
492
            String typeDesc = cp.getInternalName(type & BASE_VALUE);
1✔
493
            s = OBJECT | cp.addNormalType(typeDesc);
1✔
494
        } else {
1✔
495
            return type;
1✔
496
        }
497

498
        for (int j = 0; j < initializationCount; j++) {
1✔
499
            int u = initializations[j];
1✔
500
            int dim = u & DIM;
1✔
501
            int kind = u & KIND;
1✔
502

503
            if (kind == LOCAL) {
1✔
504
                u = dim + inputLocals[u & VALUE];
1✔
505
            } else if (kind == STACK) {
1✔
506
                u = dim + inputStack[inputStack.length - (u & VALUE)];
1✔
507
            }
508

509
            if (type == u) {
1✔
510
                return s;
1✔
511
            }
512
        }
513

514
        return type;
1✔
515
    }
516

517
    /**
518
     * Simulates the action of an xLOAD or xSTORE instruction on the output stack frame.
519
     *
520
     * @param opcode
521
     *            the opcode of the instruction
522
     * @param varIndex
523
     *            the local variable index
524
     */
525
    void executeVAR(int opcode, @NonNegative int varIndex) {
526
        // noinspection SwitchStatementWithoutDefaultBranch
527
        switch (opcode) {
1!
528
            case ILOAD:
529
                push(INTEGER);
1✔
530
                break;
1✔
531
            case LLOAD:
532
                push(LONG);
1✔
533
                push(TOP);
1✔
534
                break;
1✔
535
            case FLOAD:
536
                push(FLOAT);
1✔
537
                break;
1✔
538
            case DLOAD:
539
                push(DOUBLE);
1✔
540
                push(TOP);
1✔
541
                break;
1✔
542
            case ALOAD:
543
                push(get(varIndex));
1✔
544
                break;
1✔
545
            case ISTORE:
546
            case FSTORE:
547
            case ASTORE:
548
                executeSingleWordStore(varIndex);
1✔
549
                break;
1✔
550
            case LSTORE:
551
            case DSTORE:
552
                executeDoubleWordStore(varIndex);
1✔
553
        }
554
    }
1✔
555

556
    /**
557
     * Returns the output frame local variable type at the given index.
558
     */
559
    @NonNegative
560
    private int get(@NonNegative int localIndex) {
561
        if (outputLocals == null || localIndex >= outputLocals.length) {
1✔
562
            // This local has never been assigned in this basic block, so it's still equal to its value in the input
563
            // frame.
564
            return LOCAL | localIndex;
1✔
565
        }
566

567
        int type = outputLocals[localIndex];
1✔
568

569
        if (type == 0) {
1✔
570
            // This local has never been assigned in this basic block, so it's still equal to its value in the input
571
            // frame.
572
            type = outputLocals[localIndex] = LOCAL | localIndex;
1✔
573
        }
574

575
        return type;
1✔
576
    }
577

578
    private void executeSingleWordStore(@NonNegative int arg) {
579
        int type1 = pop();
1✔
580
        set(arg, type1);
1✔
581
        executeStore(arg);
1✔
582
    }
1✔
583

584
    private void executeDoubleWordStore(@NonNegative int arg) {
585
        pop(1);
1✔
586

587
        int type1 = pop();
1✔
588
        set(arg, type1);
1✔
589
        set(arg + 1, TOP);
1✔
590

591
        executeStore(arg);
1✔
592
    }
1✔
593

594
    private void executeStore(@NonNegative int arg) {
595
        if (arg > 0) {
1✔
596
            int type2 = get(arg - 1);
1✔
597

598
            // If type2 is of kind STACK or LOCAL we cannot know its size!
599
            if (type2 == LONG || type2 == DOUBLE) {
1!
600
                set(arg - 1, TOP);
×
601
            } else if ((type2 & KIND) != BASE) {
1✔
602
                set(arg - 1, type2 | TOP_IF_LONG_OR_DOUBLE);
1✔
603
            }
604
        }
605
    }
1✔
606

607
    /**
608
     * Simulates the action of a conditional/unconditional jump instruction on the output stack frame.
609
     */
610
    void executeJUMP(@NonNegative int opcode) {
611
        // noinspection SwitchStatementWithoutDefaultBranch
612
        switch (opcode) {
1✔
613
            case IFEQ:
614
            case IFNE:
615
            case IFLT:
616
            case IFGE:
617
            case IFGT:
618
            case IFLE:
619
            case IFNULL:
620
            case IFNONNULL:
621
                pop(1);
1✔
622
                break;
1✔
623
            case IF_ICMPEQ:
624
            case IF_ICMPNE:
625
            case IF_ICMPLT:
626
            case IF_ICMPGE:
627
            case IF_ICMPGT:
628
            case IF_ICMPLE:
629
            case IF_ACMPEQ:
630
            case IF_ACMPNE:
631
                pop(2);
1✔
632
        }
633
    }
1✔
634

635
    /**
636
     * Simulates the action of the given zero-operand instruction on the output stack frame.
637
     */
638
    @SuppressWarnings({ "OverlyComplexMethod", "OverlyLongMethod" })
639
    public void execute(@NonNegative int opcode) {
640
        // noinspection SwitchStatementWithoutDefaultBranch
641
        switch (opcode) {
1!
642
            case NOP:
643
            case INEG:
644
            case LNEG:
645
            case FNEG:
646
            case DNEG:
647
            case I2B:
648
            case I2C:
649
            case I2S:
650
            case GOTO:
651
            case RETURN:
652
                break;
1✔
653
            case ACONST_NULL:
654
                push(NULL);
1✔
655
                break;
1✔
656
            case ICONST_M1:
657
            case ICONST_0:
658
            case ICONST_1:
659
            case ICONST_2:
660
            case ICONST_3:
661
            case ICONST_4:
662
            case ICONST_5:
663
                push(INTEGER);
1✔
664
                break;
1✔
665
            case LCONST_0:
666
            case LCONST_1:
667
                push(LONG);
1✔
668
                push(TOP);
1✔
669
                break;
1✔
670
            case FCONST_0:
671
            case FCONST_1:
672
            case FCONST_2:
673
                push(FLOAT);
1✔
674
                break;
1✔
675
            case DCONST_0:
676
            case DCONST_1:
677
                push(DOUBLE);
1✔
678
                push(TOP);
1✔
679
                break;
1✔
680
            case IALOAD:
681
            case BALOAD:
682
            case CALOAD:
683
            case SALOAD:
684
                pop(2);
1✔
685
                push(INTEGER);
1✔
686
                break;
1✔
687
            case LALOAD:
688
            case D2L:
689
                pop(2);
1✔
690
                push(LONG);
1✔
691
                push(TOP);
1✔
692
                break;
1✔
693
            case FALOAD:
694
                pop(2);
×
695
                push(FLOAT);
×
696
                break;
×
697
            case DALOAD:
698
            case L2D:
699
                pop(2);
1✔
700
                push(DOUBLE);
1✔
701
                push(TOP);
1✔
702
                break;
1✔
703
            case AALOAD:
704
                executeAALOAD();
1✔
705
                break;
1✔
706
            case IASTORE:
707
            case BASTORE:
708
            case CASTORE:
709
            case SASTORE:
710
            case FASTORE:
711
            case AASTORE:
712
                pop(3);
1✔
713
                break;
1✔
714
            case LASTORE:
715
            case DASTORE:
716
                pop(4);
1✔
717
                break;
1✔
718
            case POP:
719
            case IRETURN:
720
            case FRETURN:
721
            case ARETURN:
722
            case ATHROW:
723
            case MONITORENTER:
724
            case MONITOREXIT:
725
                pop(1);
1✔
726
                break;
1✔
727
            case POP2:
728
            case LRETURN:
729
            case DRETURN:
730
                pop(2);
1✔
731
                break;
1✔
732
            case DUP:
733
                executeDUP();
1✔
734
                break;
1✔
735
            case DUP_X1:
736
                executeDUP_X1();
1✔
737
                break;
1✔
738
            case DUP_X2:
739
                executeDUP_X2();
×
740
                break;
×
741
            case DUP2:
742
                executeDUP2();
1✔
743
                break;
1✔
744
            case DUP2_X1:
745
                executeDUP2_X1();
×
746
                break;
×
747
            case DUP2_X2:
748
                executeDUP2_X2();
×
749
                break;
×
750
            case SWAP:
751
                executeSWAP();
1✔
752
                break;
1✔
753
            case IADD:
754
            case ISUB:
755
            case IMUL:
756
            case IDIV:
757
            case IREM:
758
            case IAND:
759
            case IOR:
760
            case IXOR:
761
            case ISHL:
762
            case ISHR:
763
            case IUSHR:
764
            case L2I:
765
            case D2I:
766
            case FCMPL:
767
            case FCMPG:
768
                pop(2);
1✔
769
                push(INTEGER);
1✔
770
                break;
1✔
771
            case LADD:
772
            case LSUB:
773
            case LMUL:
774
            case LDIV:
775
            case LREM:
776
            case LAND:
777
            case LOR:
778
            case LXOR:
779
                pop(4);
1✔
780
                push(LONG);
1✔
781
                push(TOP);
1✔
782
                break;
1✔
783
            case FADD:
784
            case FSUB:
785
            case FMUL:
786
            case FDIV:
787
            case FREM:
788
            case L2F:
789
            case D2F:
790
                pop(2);
×
791
                push(FLOAT);
×
792
                break;
×
793
            case DADD:
794
            case DSUB:
795
            case DMUL:
796
            case DDIV:
797
            case DREM:
798
                pop(4);
1✔
799
                push(DOUBLE);
1✔
800
                push(TOP);
1✔
801
                break;
1✔
802
            case LSHL:
803
            case LSHR:
804
            case LUSHR:
805
                pop(3);
1✔
806
                push(LONG);
1✔
807
                push(TOP);
1✔
808
                break;
1✔
809
            case I2L:
810
            case F2L:
811
                pop(1);
1✔
812
                push(LONG);
1✔
813
                push(TOP);
1✔
814
                break;
1✔
815
            case I2F:
816
                pop(1);
×
817
                push(FLOAT);
×
818
                break;
×
819
            case I2D:
820
            case F2D:
821
                pop(1);
1✔
822
                push(DOUBLE);
1✔
823
                push(TOP);
1✔
824
                break;
1✔
825
            case F2I:
826
            case ARRAYLENGTH:
827
                pop(1);
1✔
828
                push(INTEGER);
1✔
829
                break;
1✔
830
            case LCMP:
831
            case DCMPL:
832
            case DCMPG:
833
                pop(4);
1✔
834
                push(INTEGER);
1✔
835
        }
836
    }
1✔
837

838
    private void executeAALOAD() {
839
        pop(1);
1✔
840
        int type = pop();
1✔
841
        push(ELEMENT_OF + type);
1✔
842
    }
1✔
843

844
    private void executeDUP() {
845
        int type = pop();
1✔
846
        push(type);
1✔
847
        push(type);
1✔
848
    }
1✔
849

850
    private void executeDUP_X1() {
851
        int type1 = pop();
1✔
852
        int type2 = pop();
1✔
853
        push(type1);
1✔
854
        push(type2);
1✔
855
        push(type1);
1✔
856
    }
1✔
857

858
    private void executeDUP_X2() {
859
        int t1 = pop();
×
860
        int t2 = pop();
×
861
        int t3 = pop();
×
862
        push(t1);
×
863
        push(t3);
×
864
        push(t2);
×
865
        push(t1);
×
866
    }
×
867

868
    private void executeDUP2() {
869
        int t1 = pop();
1✔
870
        int t2 = pop();
1✔
871
        push(t2);
1✔
872
        push(t1);
1✔
873
        push(t2);
1✔
874
        push(t1);
1✔
875
    }
1✔
876

877
    private void executeDUP2_X1() {
878
        int t1 = pop();
×
879
        int t2 = pop();
×
880
        int t3 = pop();
×
881
        push(t2);
×
882
        push(t1);
×
883
        push(t3);
×
884
        push(t2);
×
885
        push(t1);
×
886
    }
×
887

888
    private void executeDUP2_X2() {
889
        int t1 = pop();
×
890
        int t2 = pop();
×
891
        int t3 = pop();
×
892
        int t4 = pop();
×
893
        push(t2);
×
894
        push(t1);
×
895
        push(t4);
×
896
        push(t3);
×
897
        push(t2);
×
898
        push(t1);
×
899
    }
×
900

901
    private void executeSWAP() {
902
        int t1 = pop();
1✔
903
        int t2 = pop();
1✔
904
        push(t1);
1✔
905
        push(t2);
1✔
906
    }
1✔
907

908
    /**
909
     * Simulates the action of an LCD instruction on the output stack frame.
910
     *
911
     * @param item
912
     *            the operand of the instructions
913
     */
914
    void executeLDC(@NonNull Item item) {
915
        switch (item.getType()) {
1!
916
            case ConstantPoolTypes.INTEGER:
917
                push(INTEGER);
1✔
918
                break;
1✔
919
            case ConstantPoolTypes.LONG:
920
                push(LONG);
1✔
921
                push(TOP);
1✔
922
                break;
1✔
923
            case ConstantPoolTypes.FLOAT:
924
                push(FLOAT);
1✔
925
                break;
1✔
926
            case ConstantPoolTypes.DOUBLE:
927
                push(DOUBLE);
1✔
928
                push(TOP);
1✔
929
                break;
1✔
930
            case ConstantPoolTypes.CLASS:
931
                push(OBJECT | cp.addNormalType("java/lang/Class"));
1✔
932
                break;
1✔
933
            case ConstantPoolTypes.STRING:
934
                push(OBJECT | cp.addNormalType("java/lang/String"));
1✔
935
                break;
1✔
936
            case ConstantPoolTypes.METHOD_TYPE:
937
                push(OBJECT | cp.addNormalType("java/lang/invoke/MethodType"));
×
938
                break;
×
939
            case ConstantPoolTypes.METHOD_HANDLE:
940
                push(OBJECT | cp.addNormalType("java/lang/invoke/MethodHandle"));
×
941
                break;
×
942
            case ConstantPoolTypes.DYNAMIC:
943
                DynamicItem dynamicItem = (DynamicItem) item;
1✔
944
                String desc = dynamicItem.getDesc();
1✔
945
                if (desc.length() == 1) {
1!
946
                    // primitive
947
                    char descChar = desc.charAt(0);
×
948
                    switch (descChar) {
×
949
                        case 'Z':
950
                        case 'B':
951
                        case 'S':
952
                        case 'I':
953
                            push(INTEGER);
×
954
                            break;
×
955
                        case 'F':
956
                            push(FLOAT);
×
957
                            break;
×
958
                        case 'D':
959
                            push(DOUBLE);
×
960
                            break;
×
961
                        case 'J':
962
                            push(LONG);
×
963
                            break;
×
964
                        default:
965
                            throw new IllegalArgumentException("Unsupported dynamic local 'primitive' type: " + desc);
×
966
                    }
967
                } else if (desc.charAt(0) == '[') {
1!
968
                    // array
969
                    ArrayType arrayType = ArrayType.create(desc);
×
970
                    JavaType elementType = arrayType.getElementType();
×
971
                    int mask;
972
                    if (elementType instanceof PrimitiveType) {
×
973
                        PrimitiveType primitiveElementType = (PrimitiveType) elementType;
×
974
                        char descChar = primitiveElementType.getTypeCode();
×
975
                        switch (descChar) {
×
976
                            case 'Z':
977
                            case 'B':
978
                            case 'C':
979
                            case 'S':
980
                            case 'I':
981
                                mask = INTEGER;
×
982
                                break;
×
983
                            case 'F':
984
                                mask = FLOAT;
×
985
                                break;
×
986
                            case 'D':
987
                                mask = DOUBLE;
×
988
                                break;
×
989
                            case 'J':
990
                                mask = LONG;
×
991
                                break;
×
992
                            default:
993
                                throw new IllegalArgumentException(
×
994
                                        "Unsupported array element 'primitive' type: " + desc);
995
                        }
996
                    } else {
×
997
                        mask = OBJECT;
×
998
                    }
999
                    push(ARRAY_OF | mask);
×
1000
                } else {
×
1001
                    // object, substring 'L' and ';'
1002
                    push(OBJECT | cp.addNormalType(desc.substring(1, desc.length() - 1)));
1✔
1003
                }
1004
                break;
1✔
1005
            default:
1006
                throw new IllegalArgumentException("Unknown item type, cannot execute frame: " + item.getType());
×
1007
        }
1008
    }
1✔
1009

1010
    /**
1011
     * Simulates the action of a NEW, ANEWARRAY, CHECKCAST or INSTANCEOF instruction on the output stack frame.
1012
     *
1013
     * @param opcode
1014
     *            the opcode of the instruction
1015
     * @param codeLength
1016
     *            the operand of the instruction, if any
1017
     * @param item
1018
     *            the operand of the instruction
1019
     */
1020
    void executeTYPE(@NonNegative int opcode, @NonNegative int codeLength, @NonNull StringItem item) {
1021
        // noinspection SwitchStatementWithoutDefaultBranch
1022
        switch (opcode) {
1!
1023
            case NEW:
1024
                push(UNINITIALIZED | cp.addUninitializedType(item.getValue(), codeLength));
1✔
1025
                break;
1✔
1026
            case ANEWARRAY:
1027
                executeANewArray(item);
1✔
1028
                break;
1✔
1029
            case CHECKCAST:
1030
                executeCheckCast(item);
1✔
1031
                break;
1✔
1032
            case INSTANCEOF:
1033
                pop(1);
1✔
1034
                push(INTEGER);
1✔
1035
        }
1036
    }
1✔
1037

1038
    private void executeANewArray(@NonNull StringItem item) {
1039
        String s = item.getValue();
1✔
1040
        pop();
1✔
1041

1042
        if (s.charAt(0) == '[') {
1✔
1043
            push('[' + s);
1✔
1044
        } else {
1045
            push(ARRAY_OF | OBJECT | cp.addNormalType(s));
1✔
1046
        }
1047
    }
1✔
1048

1049
    /**
1050
     * Pushes a new type onto the output frame stack.
1051
     *
1052
     * @param desc
1053
     *            the descriptor of the type to be pushed; can also be a method descriptor (in this case this method
1054
     *            pushes its return type onto the output frame stack)
1055
     */
1056
    private void push(@NonNull String desc) {
1057
        int type = getTypeEncoding(desc);
1✔
1058

1059
        if (type != 0) {
1✔
1060
            push(type);
1✔
1061

1062
            if (type == LONG || type == DOUBLE) {
1✔
1063
                push(TOP);
1✔
1064
            }
1065
        }
1066
    }
1✔
1067

1068
    private void executeCheckCast(@NonNull StringItem item) {
1069
        String s = item.getValue();
1✔
1070
        pop();
1✔
1071

1072
        if (s.charAt(0) == '[') {
1✔
1073
            push(s);
1✔
1074
        } else {
1075
            push(OBJECT | cp.addNormalType(s));
1✔
1076
        }
1077
    }
1✔
1078

1079
    /**
1080
     * Simulates the action of a MULTIANEWARRAY instruction on the output stack frame.
1081
     *
1082
     * @param dims
1083
     *            the number of dimensions of the array
1084
     * @param arrayType
1085
     *            the type of the array elements
1086
     */
1087
    void executeMULTIANEWARRAY(@NonNegative int dims, @NonNull StringItem arrayType) {
1088
        pop(dims);
1✔
1089
        push(arrayType.getValue());
1✔
1090
    }
1✔
1091

1092
    /**
1093
     * Simulates the action of the given instruction on the output stack frame.
1094
     *
1095
     * @param opcode
1096
     *            the opcode of the instruction
1097
     * @param item
1098
     *            the operand of the instruction
1099
     */
1100
    public void execute(@NonNegative int opcode, @NonNull TypeOrMemberItem item) {
1101
        if (opcode == INVOKEDYNAMIC) {
1✔
1102
            executeInvokeDynamic(item);
1✔
1103
        } else {
1104
            // noinspection SwitchStatementWithoutDefaultBranch
1105
            switch (opcode) {
1!
1106
                case GETSTATIC:
1107
                    push(item.getDesc());
1✔
1108
                    break;
1✔
1109
                case PUTSTATIC:
1110
                    pop(item.getDesc());
1✔
1111
                    break;
1✔
1112
                case GETFIELD:
1113
                    pop(1);
1✔
1114
                    push(item.getDesc());
1✔
1115
                    break;
1✔
1116
                case PUTFIELD:
1117
                    pop(item.getDesc());
1✔
1118
                    pop();
1✔
1119
                    break;
1✔
1120
                case INVOKEVIRTUAL:
1121
                case INVOKESPECIAL:
1122
                case INVOKESTATIC:
1123
                case INVOKEINTERFACE:
1124
                    executeInvoke(opcode, item);
1✔
1125
            }
1126
        }
1127
    }
1✔
1128

1129
    private void executeInvoke(@NonNegative int opcode, @NonNull TypeOrMemberItem item) {
1130
        String methodDesc = item.getDesc();
1✔
1131
        pop(methodDesc);
1✔
1132

1133
        if (opcode != INVOKESTATIC) {
1✔
1134
            int var = pop();
1✔
1135

1136
            if (opcode == INVOKESPECIAL && item.getName().charAt(0) == '<') {
1✔
1137
                init(var);
1✔
1138
            }
1139
        }
1140

1141
        push(methodDesc);
1✔
1142
    }
1✔
1143

1144
    private void executeInvokeDynamic(@NonNull TypeOrMemberItem item) {
1145
        String desc = item.getDesc();
1✔
1146
        pop(desc);
1✔
1147
        push(desc);
1✔
1148
    }
1✔
1149

1150
    /**
1151
     * Merges the input frame of the given basic block with the input and output frames of this basic block.
1152
     *
1153
     * @param frame
1154
     *            the basic block whose input frame must be updated
1155
     * @param edge
1156
     *            the kind of the {@link Edge} between this label and 'label'; see {@link Edge#info}
1157
     *
1158
     * @return <code>true</code> if the input frame of the given label has been changed by this operation
1159
     */
1160
    boolean merge(@NonNull String classDesc, @NonNull Frame frame, @NonNegative int edge) {
1161
        int nLocal = inputLocals.length;
1✔
1162
        int nStack = inputStack.length;
1✔
1163
        boolean changed = false;
1✔
1164

1165
        if (frame.inputLocals == null) {
1✔
1166
            frame.inputLocals = new int[nLocal];
1✔
1167
            changed = true;
1✔
1168
        }
1169

1170
        int i;
1171
        int s;
1172
        int dim;
1173
        int type;
1174

1175
        for (i = 0; i < nLocal; i++) {
1✔
1176
            if (outputLocals != null && i < outputLocals.length) {
1✔
1177
                s = outputLocals[i];
1✔
1178

1179
                if (s == 0) {
1✔
1180
                    type = inputLocals[i];
1✔
1181
                } else {
1182
                    dim = s & DIM;
1✔
1183
                    int kind = s & KIND;
1✔
1184

1185
                    if (kind == BASE) {
1✔
1186
                        type = s;
1✔
1187
                    } else {
1188
                        if (kind == LOCAL) {
1✔
1189
                            type = dim + inputLocals[s & VALUE];
1✔
1190
                        } else {
1191
                            type = dim + inputStack[nStack - (s & VALUE)];
1✔
1192
                        }
1193

1194
                        if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (type == LONG || type == DOUBLE)) {
1!
1195
                            type = TOP;
×
1196
                        }
1197
                    }
1198
                }
1✔
1199
            } else {
1200
                type = inputLocals[i];
1✔
1201
            }
1202

1203
            if (initializations != null) {
1✔
1204
                type = init(classDesc, type);
1✔
1205
            }
1206

1207
            changed |= merge(type, frame.inputLocals, i);
1✔
1208
        }
1209

1210
        if (edge > 0) {
1✔
1211
            for (i = 0; i < nLocal; ++i) {
1✔
1212
                type = inputLocals[i];
1✔
1213
                changed |= merge(type, frame.inputLocals, i);
1✔
1214
            }
1215

1216
            if (frame.inputStack == null) {
1✔
1217
                frame.inputStack = new int[1];
1✔
1218
                changed = true;
1✔
1219
            }
1220

1221
            changed |= merge(edge, frame.inputStack, 0);
1✔
1222
            return changed;
1✔
1223
        }
1224

1225
        int nInputStack = inputStack.length + owner.inputStackTop;
1✔
1226

1227
        if (frame.inputStack == null) {
1✔
1228
            frame.inputStack = new int[nInputStack + outputStackTop];
1✔
1229
            changed = true;
1✔
1230
        }
1231

1232
        for (i = 0; i < nInputStack; i++) {
1✔
1233
            type = inputStack[i];
1✔
1234

1235
            if (initializations != null) {
1✔
1236
                type = init(classDesc, type);
1✔
1237
            }
1238

1239
            changed |= merge(type, frame.inputStack, i);
1✔
1240
        }
1241

1242
        for (i = 0; i < outputStackTop; i++) {
1✔
1243
            s = outputStack[i];
1✔
1244
            dim = s & DIM;
1✔
1245
            int kind = s & KIND;
1✔
1246

1247
            if (kind == BASE) {
1✔
1248
                type = s;
1✔
1249
            } else {
1250
                if (kind == LOCAL) {
1✔
1251
                    type = dim + inputLocals[s & VALUE];
1✔
1252
                } else {
1253
                    type = dim + inputStack[nStack - (s & VALUE)];
1✔
1254
                }
1255

1256
                if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (type == LONG || type == DOUBLE)) {
1!
1257
                    type = TOP;
×
1258
                }
1259
            }
1260

1261
            if (initializations != null) {
1✔
1262
                type = init(classDesc, type);
1✔
1263
            }
1264

1265
            changed |= merge(type, frame.inputStack, nInputStack + i);
1✔
1266
        }
1267

1268
        return changed;
1✔
1269
    }
1270

1271
    /**
1272
     * Merges the type at the given index in the given type array with the given type.
1273
     *
1274
     * @param type1
1275
     *            the type with which the type array element must be merged
1276
     * @param types
1277
     *            an array of types
1278
     * @param index
1279
     *            the index of the type that must be merged in 'types'
1280
     *
1281
     * @return <code>true</code> if the type array has been modified by this operation
1282
     */
1283
    private boolean merge(@NonNegative int type1, @NonNull int[] types, @NonNegative int index) {
1284
        int type2 = types[index];
1✔
1285

1286
        if (type2 == type1) {
1✔
1287
            // If the types are equal, there is no change.
1288
            return false;
1✔
1289
        }
1290

1291
        if ((type1 & ~DIM) == NULL) {
1✔
1292
            if (type2 == NULL) {
1!
1293
                return false;
×
1294
            }
1295

1296
            // noinspection AssignmentToMethodParameter
1297
            type1 = NULL;
1✔
1298
        }
1299

1300
        if (type2 == 0) {
1✔
1301
            // If types[index] has never been assigned, merge(type2, type1) = type1.
1302
            types[index] = type1;
1✔
1303
            return true;
1✔
1304
        }
1305

1306
        int v;
1307

1308
        if ((type2 & BASE_KIND) == OBJECT || (type2 & DIM) != 0) {
1✔
1309
            // If type2 is a reference type of any dimension.
1310
            if (type1 == NULL) {
1✔
1311
                // If type1 is the NULL type, merge(type2, type1) = type2, so there is no change.
1312
                return false;
1✔
1313
            }
1314
            if ((type1 & (DIM | BASE_KIND)) == (type2 & (DIM | BASE_KIND))) {
1✔
1315
                // If type1 and type2 have the same dimension and same base kind.
1316
                if ((type2 & BASE_KIND) == OBJECT) {
1!
1317
                    // If type1 is also a reference type, and if type2 and type1 have the same dimension
1318
                    // merge(type2, type1) = dim(type1) | common parent of the element types of type2 and type1.
1319
                    v = type1 & DIM | OBJECT | cp.getMergedType(type1 & BASE_VALUE, type2 & BASE_VALUE);
1✔
1320
                } else {
1321
                    // If type2 and type1 are array types, but not with the same element type,
1322
                    // merge(type2, type1) = dim(type2) - 1 | java/lang/Object.
1323
                    int dim = ELEMENT_OF + (type2 & DIM);
×
1324
                    v = dim | OBJECT | cp.addNormalType("java/lang/Object");
×
1325
                }
×
1326
            } else if ((type1 & BASE_KIND) == OBJECT || (type1 & DIM) != 0) {
1!
1327
                // If type1 is any other reference or array type, the merged type is min(uDim, tDim) | java/lang/Object,
1328
                // where uDim is the array dimension of type2, minus 1 if type2 is an array type with a primitive
1329
                // element
1330
                // type (and similarly for tDim).
1331
                int tDim = ((type1 & DIM) == 0 || (type1 & BASE_KIND) == OBJECT ? 0 : ELEMENT_OF) + (type1 & DIM);
1!
1332
                int uDim = ((type2 & DIM) == 0 || (type2 & BASE_KIND) == OBJECT ? 0 : ELEMENT_OF) + (type2 & DIM);
1!
1333
                v = Math.min(tDim, uDim) | OBJECT | cp.addNormalType("java/lang/Object");
1✔
1334
            } else {
1✔
1335
                // If type1 is any other type, merge(type2, type1) = TOP.
1336
                v = TOP;
1✔
1337
            }
1338
        } else if (type2 == NULL) {
1✔
1339
            // If type2 is the NULL type, merge(type2, type1) = type1, or TOP if type1 is not a reference type.
1340
            v = (type1 & BASE_KIND) == OBJECT || (type1 & DIM) != 0 ? type1 : TOP;
1✔
1341
        } else {
1342
            // If type2 is any other type, merge(type2, type1) = TOP whatever type1.
1343
            v = TOP;
1✔
1344
        }
1345

1346
        if (type2 != v) {
1✔
1347
            types[index] = v;
1✔
1348
            return true;
1✔
1349
        }
1350

1351
        return false;
1✔
1352
    }
1353
}
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