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

hazendaz / jmockit1 / 418

30 Oct 2025 05:08PM UTC coverage: 72.206%. Remained the same
418

push

github

hazendaz
Use primative boolean instead of Boolean as not needed for the cast

5683 of 8360 branches covered (67.98%)

Branch coverage included in aggregate %.

0 of 1 new or added line in 1 file covered. (0.0%)

11946 of 16055 relevant lines covered (74.41%)

0.74 hits per line

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

86.14
/main/src/main/java/mockit/asm/constantPool/ConstantPoolGeneration.java
1
package mockit.asm.constantPool;
2

3
import static mockit.asm.jvmConstants.ConstantPoolTypes.CLASS;
4
import static mockit.asm.jvmConstants.ConstantPoolTypes.DOUBLE;
5
import static mockit.asm.jvmConstants.ConstantPoolTypes.FIELD_REF;
6
import static mockit.asm.jvmConstants.ConstantPoolTypes.FLOAT;
7
import static mockit.asm.jvmConstants.ConstantPoolTypes.IMETHOD_REF;
8
import static mockit.asm.jvmConstants.ConstantPoolTypes.INTEGER;
9
import static mockit.asm.jvmConstants.ConstantPoolTypes.LONG;
10
import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_HANDLE;
11
import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_REF;
12
import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_TYPE;
13
import static mockit.asm.jvmConstants.ConstantPoolTypes.NAME_TYPE;
14
import static mockit.asm.jvmConstants.ConstantPoolTypes.STRING;
15
import static mockit.asm.jvmConstants.ConstantPoolTypes.UTF8;
16
import static mockit.internal.util.ClassLoad.OBJECT;
17

18
import edu.umd.cs.findbugs.annotations.NonNull;
19
import edu.umd.cs.findbugs.annotations.Nullable;
20

21
import mockit.asm.jvmConstants.ConstantPoolTypes;
22
import mockit.asm.types.JavaType;
23
import mockit.asm.types.MethodType;
24
import mockit.asm.types.PrimitiveType;
25
import mockit.asm.types.ReferenceType;
26
import mockit.asm.util.ByteVector;
27
import mockit.asm.util.MethodHandle;
28
import mockit.internal.util.ClassLoad;
29

30
import org.checkerframework.checker.index.qual.NonNegative;
31

32
/**
33
 * Allows the constant pool for a classfile to be created from scratch, when that classfile itself is being generated or
34
 * modified from an existing class file.
35
 */
36
@SuppressWarnings({ "ClassWithTooManyFields", "OverlyCoupledClass" })
37
public final class ConstantPoolGeneration {
38
    /**
39
     * The constant pool of the class file being generated/modified.
40
     */
41
    @NonNull
42
    private final ByteVector pool;
43

44
    /**
45
     * The constant pool's hash table data.
46
     */
47
    @NonNull
48
    private Item[] items;
49

50
    /**
51
     * The threshold of the constant pool's hash table.
52
     */
53
    @NonNegative
54
    private int threshold;
55

56
    /**
57
     * Index of the next item to be added in the constant pool.
58
     */
59
    @NonNegative
60
    private int index;
61

62
    @NonNull
63
    private final StringItem reusableUTF8Item;
64
    @NonNull
65
    private final StringItem reusableStringItem;
66
    @NonNull
67
    private final NameAndTypeItem reusableNameTypeItem;
68
    @NonNull
69
    private final ClassMemberItem reusableClassMemberItem;
70
    @NonNull
71
    private final IntItem reusableIntItem;
72
    @NonNull
73
    private final LongItem reusableLongItem;
74
    @NonNull
75
    private final FloatItem reusableFloatItem;
76
    @NonNull
77
    private final DoubleItem reusableDoubleItem;
78
    @NonNull
79
    private final MethodHandleItem reusableMethodHandleItem;
80
    @NonNull
81
    private final DynamicItem reusableDynamicItem;
82

83
    /**
84
     * A type table used to temporarily store internal names that will not necessarily be stored in the constant pool.
85
     * This type table is used by the control flow and data flow analysis algorithm to compute stack map frames from
86
     * scratch. This array associates to each index <code>i</code> the <code>TypeTableItem</code> whose index is
87
     * <code>i</code>. All <code>TypeTableItem</code> objects stored in this array are also stored in the {@link #items}
88
     * hash table. These two arrays allow to retrieve an <code>Item</code> from its index or, conversely, to get the
89
     * index of an <code>Item</code> from its value. Each <code>TypeTableItem</code> stores an internal name in its
90
     * {@link TypeTableItem#typeDesc} field.
91
     */
92
    private TypeTableItem[] typeTable;
93

94
    /**
95
     * Number of elements in the {@link #typeTable} array.
96
     */
97
    private short typeCount;
98

99
    @NonNull
100
    private final NormalTypeTableItem reusableNormalItem;
101
    @NonNull
102
    private final UninitializedTypeTableItem reusableUninitializedItem;
103
    @NonNull
104
    private final MergedTypeTableItem reusableMergedItem;
105

106
    @SuppressWarnings("OverlyCoupledMethod")
107
    public ConstantPoolGeneration() {
1✔
108
        pool = new ByteVector();
1✔
109
        items = new Item[256];
1✔
110
        // noinspection NumericCastThatLosesPrecision
111
        threshold = (int) (0.75d * items.length);
1✔
112
        index = 1;
1✔
113
        reusableUTF8Item = new StringItem();
1✔
114
        reusableStringItem = new StringItem();
1✔
115
        reusableNameTypeItem = new NameAndTypeItem(0);
1✔
116
        reusableClassMemberItem = new ClassMemberItem(0);
1✔
117
        reusableIntItem = new IntItem(0);
1✔
118
        reusableLongItem = new LongItem(0);
1✔
119
        reusableFloatItem = new FloatItem(0);
1✔
120
        reusableDoubleItem = new DoubleItem(0);
1✔
121
        reusableMethodHandleItem = new MethodHandleItem(0);
1✔
122
        reusableDynamicItem = new DynamicItem(0);
1✔
123
        reusableNormalItem = new NormalTypeTableItem();
1✔
124
        reusableUninitializedItem = new UninitializedTypeTableItem();
1✔
125
        reusableMergedItem = new MergedTypeTableItem();
1✔
126
    }
1✔
127

128
    /**
129
     * Adds an UTF8 string to the constant pool of the class being built. Does nothing if the constant pool already
130
     * contains a similar item.
131
     *
132
     * @param value
133
     *            the String value.
134
     *
135
     * @return the index of a new or already existing UTF8 item.
136
     */
137
    @NonNegative
138
    public int newUTF8(@NonNull String value) {
139
        reusableUTF8Item.set(UTF8, value);
1✔
140

141
        StringItem result = get(reusableUTF8Item);
1✔
142

143
        if (result == null) {
1✔
144
            pool.putByte(UTF8).putUTF8(value);
1✔
145

146
            result = new StringItem(index++, reusableUTF8Item);
1✔
147
            put(result);
1✔
148
        }
149

150
        return result.index;
1✔
151
    }
152

153
    /**
154
     * Adds a class reference to the constant pool of the class being built. Does nothing if the constant pool already
155
     * contains a similar item.
156
     *
157
     * @param internalName
158
     *            the internal name of the class.
159
     *
160
     * @return the index of a new or already existing class reference item.
161
     */
162
    @NonNegative
163
    public int newClass(@NonNull String internalName) {
164
        return newClassItem(internalName).index;
1✔
165
    }
166

167
    /**
168
     * Adds a class reference to the constant pool of the class being built. Does nothing if the constant pool already
169
     * contains a similar item.
170
     *
171
     * @param internalName
172
     *            the internal name of the class.
173
     *
174
     * @return a new or already existing class reference item.
175
     */
176
    @NonNull
177
    public StringItem newClassItem(@NonNull String internalName) {
178
        return newStringItem(CLASS, internalName);
1✔
179
    }
180

181
    /**
182
     * Adds a string to the constant pool of the class being built. Does nothing if the constant pool already contains a
183
     * similar item.
184
     *
185
     * @param type
186
     *            one of {@link ConstantPoolTypes#STRING}, {@link ConstantPoolTypes#CLASS} or
187
     *            {@link ConstantPoolTypes#METHOD_TYPE}
188
     * @param value
189
     *            the String value.
190
     *
191
     * @return a new or already existing string item.
192
     */
193
    @NonNull
194
    private StringItem newStringItem(int type, @NonNull String value) {
195
        reusableStringItem.set(type, value);
1✔
196

197
        StringItem result = get(reusableStringItem);
1✔
198

199
        if (result == null) {
1✔
200
            int itemIndex = newUTF8(value);
1✔
201
            pool.put12(type, itemIndex);
1✔
202

203
            result = new StringItem(index++, reusableStringItem);
1✔
204
            put(result);
1✔
205
        }
206

207
        return result;
1✔
208
    }
209

210
    /**
211
     * Adds a method handle to the constant pool of the class being built. Does nothing if the constant pool already
212
     * contains a similar item.
213
     *
214
     * @return a new or an already existing method type reference item.
215
     */
216
    @NonNull
217
    public MethodHandleItem newMethodHandleItem(@NonNull MethodHandle methodHandle) {
218
        reusableMethodHandleItem.set(methodHandle);
1✔
219

220
        MethodHandleItem result = get(reusableMethodHandleItem);
1✔
221

222
        if (result == null) {
1!
223
            int tag = methodHandle.tag;
×
224
            int memberType = tag == MethodHandle.Tag.TAG_INVOKEINTERFACE ? IMETHOD_REF : METHOD_REF;
×
225
            ClassMemberItem memberItem = newClassMemberItem(memberType, methodHandle.owner, methodHandle.name,
×
226
                    methodHandle.desc);
227
            pool.put11(METHOD_HANDLE, tag).putShort(memberItem.index);
×
228

229
            result = new MethodHandleItem(index++, reusableMethodHandleItem);
×
230
            put(result);
×
231
        }
232

233
        return result;
1✔
234
    }
235

236
    @NonNull
237
    private ClassMemberItem newClassMemberItem(int type, @NonNull String owner, @NonNull String name,
238
            @NonNull String desc) {
239
        reusableClassMemberItem.set(type, owner, name, desc);
1✔
240

241
        ClassMemberItem result = get(reusableClassMemberItem);
1✔
242

243
        if (result == null) {
1✔
244
            int ownerItemIndex = newClass(owner);
1✔
245
            int nameAndTypeItemIndex = newNameType(name, desc);
1✔
246
            put122(type, ownerItemIndex, nameAndTypeItemIndex);
1✔
247

248
            result = new ClassMemberItem(index++, reusableClassMemberItem);
1✔
249
            put(result);
1✔
250
        }
251

252
        return result;
1✔
253
    }
254

255
    /**
256
     * Adds a field reference to the constant pool of the class being built. Does nothing if the constant pool already
257
     * contains a similar item.
258
     *
259
     * @param owner
260
     *            the internal name of the field's owner class
261
     * @param name
262
     *            the field's name
263
     * @param desc
264
     *            the field's descriptor
265
     *
266
     * @return a new or already existing field reference item
267
     */
268
    @NonNull
269
    public ClassMemberItem newFieldItem(@NonNull String owner, @NonNull String name, @NonNull String desc) {
270
        return newClassMemberItem(FIELD_REF, owner, name, desc);
1✔
271
    }
272

273
    /**
274
     * Adds a method reference to the constant pool of the class being built. Does nothing if the constant pool already
275
     * contains a similar item.
276
     *
277
     * @param owner
278
     *            the internal name of the method's owner class
279
     * @param name
280
     *            the method's name
281
     * @param desc
282
     *            the method's descriptor
283
     * @param itf
284
     *            <code>true</code> if <code>owner</code> is an interface
285
     *
286
     * @return a new or already existing method reference item
287
     */
288
    @NonNull
289
    public ClassMemberItem newMethodItem(@NonNull String owner, @NonNull String name, @NonNull String desc,
290
            boolean itf) {
291
        return newClassMemberItem(itf ? IMETHOD_REF : METHOD_REF, owner, name, desc);
1✔
292
    }
293

294
    /**
295
     * Adds an integer to the constant pool of the class being built. Does nothing if the constant pool already contains
296
     * a similar item.
297
     *
298
     * @param value
299
     *            the int value
300
     *
301
     * @return a new or already existing int item
302
     */
303
    @NonNull
304
    public IntItem newInteger(int value) {
305
        reusableIntItem.setValue(value);
1✔
306

307
        IntItem result = get(reusableIntItem);
1✔
308

309
        if (result == null) {
1✔
310
            pool.putByte(INTEGER).putInt(value);
1✔
311

312
            result = new IntItem(index++, reusableIntItem);
1✔
313
            put(result);
1✔
314
        }
315

316
        return result;
1✔
317
    }
318

319
    /**
320
     * Adds a float to the constant pool of the class being built. Does nothing if the constant pool already contains a
321
     * similar item.
322
     *
323
     * @param value
324
     *            the float value
325
     *
326
     * @return a new or already existing float item
327
     */
328
    @NonNull
329
    public FloatItem newFloat(float value) {
330
        reusableFloatItem.set(value);
1✔
331

332
        FloatItem result = get(reusableFloatItem);
1✔
333

334
        if (result == null) {
1!
335
            pool.putByte(FLOAT).putInt(reusableFloatItem.intVal);
×
336

337
            result = new FloatItem(index++, reusableFloatItem);
×
338
            put(result);
×
339
        }
340

341
        return result;
1✔
342
    }
343

344
    /**
345
     * Adds a long to the constant pool of the class being built. Does nothing if the constant pool already contains a
346
     * similar item.
347
     *
348
     * @param value
349
     *            the long value
350
     *
351
     * @return a new or already existing long item
352
     */
353
    @NonNull
354
    public LongItem newLong(long value) {
355
        reusableLongItem.setValue(value);
1✔
356

357
        LongItem result = get(reusableLongItem);
1✔
358

359
        if (result == null) {
1!
360
            pool.putByte(LONG).putLong(value);
×
361

362
            result = new LongItem(index, reusableLongItem);
×
363
            index += 2;
×
364
            put(result);
×
365
        }
366

367
        return result;
1✔
368
    }
369

370
    /**
371
     * Adds a double to the constant pool of the class being built. Does nothing if the constant pool already contains a
372
     * similar item.
373
     *
374
     * @param value
375
     *            the double value
376
     *
377
     * @return a new or already existing double item
378
     */
379
    @NonNull
380
    public DoubleItem newDouble(double value) {
381
        reusableDoubleItem.set(value);
1✔
382

383
        DoubleItem result = get(reusableDoubleItem);
1✔
384

385
        if (result == null) {
1!
386
            pool.putByte(DOUBLE).putLong(reusableDoubleItem.longVal);
×
387

388
            result = new DoubleItem(index, reusableDoubleItem);
×
389
            index += 2;
×
390
            put(result);
×
391
        }
392

393
        return result;
1✔
394
    }
395

396
    /**
397
     * Adds a name and type to the constant pool of the class being built. Does nothing if the constant pool already
398
     * contains a similar item.
399
     *
400
     * @param name
401
     *            a name
402
     * @param desc
403
     *            a type descriptor
404
     *
405
     * @return the index of a new or already existing name and type item
406
     */
407
    @NonNegative
408
    private int newNameType(@NonNull String name, @NonNull String desc) {
409
        reusableNameTypeItem.set(name, desc);
1✔
410

411
        NameAndTypeItem result = get(reusableNameTypeItem);
1✔
412

413
        if (result == null) {
1✔
414
            int nameItemIndex = newUTF8(name);
1✔
415
            int descItemIndex = newUTF8(desc);
1✔
416
            put122(NAME_TYPE, nameItemIndex, descItemIndex);
1✔
417

418
            result = new NameAndTypeItem(index++, reusableNameTypeItem);
1✔
419
            put(result);
1✔
420
        }
421

422
        return result.index;
1✔
423
    }
424

425
    /**
426
     * Adds a number or string constant to the constant pool of the class being built. Does nothing if the constant pool
427
     * already contains a similar item.
428
     *
429
     * @param cst
430
     *            the value of the constant to be added to the constant pool, which must be an {@link Integer}, a
431
     *            {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, or a {@link JavaType}
432
     *
433
     * @return a new or already existing constant item with the given value
434
     */
435
    @NonNull
436
    public Item newConstItem(@NonNull Object cst) {
437
        if (cst instanceof String) {
1✔
438
            return newStringItem(STRING, (String) cst);
1✔
439
        }
440

441
        if (cst instanceof Number) {
1✔
442
            return newNumberItem((Number) cst);
1✔
443
        }
444

445
        if (cst instanceof Character) {
1!
446
            return newInteger((Character) cst);
×
447
        }
448

449
        if (cst instanceof Boolean) {
1!
NEW
450
            int val = (boolean) cst ? 1 : 0;
×
451
            return newInteger(val);
×
452
        }
453

454
        if (cst instanceof ReferenceType) {
1✔
455
            String typeDesc = ((ReferenceType) cst).getInternalName();
1✔
456
            return cst instanceof MethodType ? newStringItem(METHOD_TYPE, typeDesc) : newClassItem(typeDesc);
1✔
457
        }
458

459
        if (cst instanceof PrimitiveType) {
1!
460
            String typeDesc = ((PrimitiveType) cst).getDescriptor();
×
461
            return newClassItem(typeDesc);
×
462
        }
463

464
        if (cst instanceof MethodHandle) {
1✔
465
            return newMethodHandleItem((MethodHandle) cst);
1✔
466
        }
467

468
        if (cst instanceof DynamicItem) {
1!
469
            DynamicItem dynamicItem = (DynamicItem) cst;
1✔
470
            return createDynamicItem(dynamicItem.type, dynamicItem.name, dynamicItem.desc, dynamicItem.bsmIndex);
1✔
471
        }
472
        throw new IllegalArgumentException("value " + cst);
×
473
    }
474

475
    @NonNull
476
    private Item newNumberItem(@NonNull Number cst) {
477
        if (cst instanceof Float) {
1✔
478
            return newFloat(cst.floatValue());
1✔
479
        }
480

481
        if (cst instanceof Long) {
1✔
482
            return newLong(cst.longValue());
1✔
483
        }
484

485
        if (cst instanceof Double) {
1✔
486
            return newDouble(cst.doubleValue());
1✔
487
        }
488

489
        return newInteger(cst.intValue());
1✔
490
    }
491

492
    /**
493
     * Adds the given internal name to {@link #typeTable} and returns its index. Does nothing if the type table already
494
     * contains this internal name.
495
     *
496
     * @param type
497
     *            the internal name to be added to the type table
498
     *
499
     * @return the index of this internal name in the type table
500
     */
501
    @NonNegative
502
    public int addNormalType(@NonNull String type) {
503
        reusableNormalItem.set(type);
1✔
504

505
        TypeTableItem result = get(reusableNormalItem);
1✔
506

507
        if (result == null) {
1✔
508
            result = new NormalTypeTableItem(++typeCount, reusableNormalItem);
1✔
509
            addToTypeTable(result);
1✔
510
        }
511

512
        return result.index;
1✔
513
    }
514

515
    /**
516
     * Adds the given "uninitialized" type to {@link #typeTable} and returns its index. This method is used for
517
     * UNINITIALIZED types, made of an internal name and a bytecode offset.
518
     *
519
     * @param type
520
     *            the internal name to be added to the type table
521
     * @param offset
522
     *            the bytecode offset of the NEW instruction that created this UNINITIALIZED type value
523
     *
524
     * @return the index of this internal name in the type table
525
     */
526
    @NonNegative
527
    public int addUninitializedType(@NonNull String type, @NonNegative int offset) {
528
        reusableUninitializedItem.set(type, offset);
1✔
529

530
        TypeTableItem result = get(reusableUninitializedItem);
1✔
531

532
        if (result == null) {
1✔
533
            result = new UninitializedTypeTableItem(++typeCount, reusableUninitializedItem);
1✔
534
            addToTypeTable(result);
1✔
535
        }
536

537
        return result.index;
1✔
538
    }
539

540
    private void addToTypeTable(@NonNull TypeTableItem newItem) {
541
        put(newItem);
1✔
542

543
        if (typeTable == null) {
1✔
544
            typeTable = new TypeTableItem[16];
1✔
545
        }
546

547
        int newItemIndex = typeCount;
1✔
548
        enlargeTypeTableIfNeeded(newItemIndex);
1✔
549
        typeTable[newItemIndex] = newItem;
1✔
550
    }
1✔
551

552
    private void enlargeTypeTableIfNeeded(@NonNegative int newItemIndex) {
553
        int currentTypeCount = typeTable.length;
1✔
554

555
        if (newItemIndex == currentTypeCount) {
1✔
556
            TypeTableItem[] newTable = new TypeTableItem[2 * currentTypeCount];
1✔
557
            System.arraycopy(typeTable, 0, newTable, 0, currentTypeCount);
1✔
558
            typeTable = newTable;
1✔
559
        }
560
    }
1✔
561

562
    /**
563
     * Returns the index of the common super type of the two given types. This method calls {@link #getCommonSuperClass}
564
     * and caches the result in the {@link #items} hash table to speedup future calls with the same parameters.
565
     *
566
     * @param type1
567
     *            index of an internal name in {@link #typeTable}
568
     * @param type2
569
     *            index of an internal name in {@link #typeTable}
570
     *
571
     * @return the index of the common super type of the two given types
572
     */
573
    @NonNegative
574
    public int getMergedType(@NonNegative int type1, @NonNegative int type2) {
575
        reusableMergedItem.set(type1, type2);
1✔
576

577
        MergedTypeTableItem result = get(reusableMergedItem);
1✔
578

579
        if (result == null) {
1✔
580
            String type1Desc = getInternalName(type1);
1✔
581
            String type2Desc = getInternalName(type2);
1✔
582
            String commonSuperClass = getCommonSuperClass(type1Desc, type2Desc);
1✔
583
            reusableMergedItem.commonSuperTypeIndex = addNormalType(commonSuperClass);
1✔
584

585
            result = new MergedTypeTableItem(reusableMergedItem);
1✔
586
            put(result);
1✔
587
        }
588

589
        return result.commonSuperTypeIndex;
1✔
590
    }
591

592
    /**
593
     * Returns the common super type of the two given types. The default implementation of this method <i>loads</i> the
594
     * two given classes and uses the java.lang.Class methods to find the common super class. It can be overridden to
595
     * compute this common super type in other ways, in particular without actually loading any class, or to take into
596
     * account the class that is currently being generated by this ClassWriter, which can of course not be loaded since
597
     * it is under construction.
598
     *
599
     * @param type1
600
     *            the internal name of a class
601
     * @param type2
602
     *            the internal name of another class
603
     *
604
     * @return the internal name of the common super class of the two given classes
605
     */
606
    @NonNull
607
    private static String getCommonSuperClass(@NonNull String type1, @NonNull String type2) {
608
        // Reimplemented to avoid "duplicate class definition" errors.
609
        String class1 = type1;
1✔
610
        String class2 = type2;
1✔
611

612
        while (true) {
613
            if (OBJECT.equals(class1) || OBJECT.equals(class2)) {
1✔
614
                return OBJECT;
1✔
615
            }
616

617
            String superClass = ClassLoad.whichIsSuperClass(class1, class2);
1✔
618

619
            if (superClass != null) {
1✔
620
                return superClass;
1✔
621
            }
622

623
            class1 = ClassLoad.getSuperClass(class1);
1✔
624
            class2 = ClassLoad.getSuperClass(class2);
1✔
625

626
            if (class1.equals(class2)) {
1✔
627
                return class1;
1✔
628
            }
629
        }
1✔
630
    }
631

632
    @NonNull
633
    public String getInternalName(@NonNegative int typeTableIndex) {
634
        TypeTableItem typeTableItem = typeTable[typeTableIndex]; // Normal or Uninitialized
1✔
635
        return typeTableItem.typeDesc;
1✔
636
    }
637

638
    @NonNull
639
    public UninitializedTypeTableItem getUninitializedItemValue(@NonNegative int typeTableIndex) {
640
        return (UninitializedTypeTableItem) typeTable[typeTableIndex];
1✔
641
    }
642

643
    @Nullable
644
    public Item getItem(@NonNegative int itemHashCode) {
645
        return items[itemHashCode % items.length];
1✔
646
    }
647

648
    /**
649
     * Returns the constant pool's hash table item which is equal to the given item.
650
     *
651
     * @param key
652
     *            a constant pool item
653
     *
654
     * @return the constant pool's hash table item which is equal to the given item, or <code>null</code> if there is no
655
     *         such item
656
     */
657
    @Nullable
658
    private <I extends Item> I get(@NonNull I key) {
659
        Item item = getItem(key.getHashCode());
1✔
660
        int keyType = key.getType();
1✔
661

662
        while (item != null && (item.getType() != keyType || !key.isEqualTo(item))) {
1✔
663
            item = item.getNext();
1✔
664
        }
665

666
        // noinspection unchecked
667
        return (I) item;
1✔
668
    }
669

670
    /**
671
     * Puts the given item in the constant pool's hash table. The hash table <i>must</i> not already contains this item.
672
     *
673
     * @param item
674
     *            the item to be added to the constant pool's hash table
675
     */
676
    private void put(@NonNull Item item) {
677
        resizeItemArrayIfNeeded();
1✔
678
        item.setNext(items);
1✔
679
    }
1✔
680

681
    private void resizeItemArrayIfNeeded() {
682
        if (index + typeCount > threshold) {
1✔
683
            int ll = items.length;
1✔
684
            int nl = ll * 2 + 1;
1✔
685
            Item[] newItems = new Item[nl];
1✔
686

687
            for (int l = ll - 1; l >= 0; l--) {
1✔
688
                Item j = items[l];
1✔
689
                put(newItems, j);
1✔
690
            }
691

692
            items = newItems;
1✔
693
            // noinspection NumericCastThatLosesPrecision
694
            threshold = (int) (nl * 0.75);
1✔
695
        }
696
    }
1✔
697

698
    private static void put(@NonNull Item[] newItems, @Nullable Item item) {
699
        while (item != null) {
1✔
700
            Item next = item.getNext();
1✔
701
            item.setNext(newItems);
1✔
702
            // noinspection AssignmentToMethodParameter
703
            item = next;
1✔
704
        }
1✔
705
    }
1✔
706

707
    /**
708
     * Puts one byte and two shorts into the constant pool.
709
     */
710
    private void put122(int b, int s1, int s2) {
711
        pool.put12(b, s1).putShort(s2);
1✔
712
    }
1✔
713

714
    @NonNegative
715
    public int getSize() {
716
        return pool.getLength();
1✔
717
    }
718

719
    public void checkConstantPoolMaxSize() {
720
        if (index > 0xFFFF) {
1!
721
            throw new RuntimeException("Class file too large!");
×
722
        }
723
    }
1✔
724

725
    public void put(@NonNull ByteVector out) {
726
        out.putShort(index).putByteVector(pool);
1✔
727
    }
1✔
728

729
    public void copy(@NonNull byte[] code, @NonNegative int off, @NonNegative int header, @NonNull Item[] cpItems) {
730
        pool.putByteArray(code, off, header - off);
1✔
731
        items = cpItems;
1✔
732

733
        int ll = cpItems.length;
1✔
734
        // noinspection NumericCastThatLosesPrecision
735
        threshold = (int) (0.75d * ll);
1✔
736
        index = ll;
1✔
737
    }
1✔
738

739
    @NonNull
740
    public DynamicItem createDynamicItem(int type, @NonNull String name, @NonNull String desc,
741
            @NonNegative int bsmIndex) {
742
        reusableDynamicItem.set(type, name, desc, bsmIndex);
1✔
743

744
        DynamicItem result = get(reusableDynamicItem);
1✔
745

746
        if (result == null) {
1!
747
            int nameAndTypeItemIndex = newNameType(name, desc);
×
748
            put122(type, bsmIndex, nameAndTypeItemIndex);
×
749

750
            result = new DynamicItem(index++, reusableDynamicItem);
×
751
            put(result);
×
752
        }
753

754
        return result;
1✔
755
    }
756
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc