• 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

86.14
/main/src/main/java/mockit/asm/constantPool/ConstantPoolGeneration.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.constantPool;
7

8
import static mockit.asm.jvmConstants.ConstantPoolTypes.CLASS;
9
import static mockit.asm.jvmConstants.ConstantPoolTypes.DOUBLE;
10
import static mockit.asm.jvmConstants.ConstantPoolTypes.FIELD_REF;
11
import static mockit.asm.jvmConstants.ConstantPoolTypes.FLOAT;
12
import static mockit.asm.jvmConstants.ConstantPoolTypes.IMETHOD_REF;
13
import static mockit.asm.jvmConstants.ConstantPoolTypes.INTEGER;
14
import static mockit.asm.jvmConstants.ConstantPoolTypes.LONG;
15
import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_HANDLE;
16
import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_REF;
17
import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_TYPE;
18
import static mockit.asm.jvmConstants.ConstantPoolTypes.NAME_TYPE;
19
import static mockit.asm.jvmConstants.ConstantPoolTypes.STRING;
20
import static mockit.asm.jvmConstants.ConstantPoolTypes.UTF8;
21
import static mockit.internal.util.ClassLoad.OBJECT;
22

23
import edu.umd.cs.findbugs.annotations.NonNull;
24
import edu.umd.cs.findbugs.annotations.Nullable;
25

26
import mockit.asm.jvmConstants.ConstantPoolTypes;
27
import mockit.asm.types.JavaType;
28
import mockit.asm.types.MethodType;
29
import mockit.asm.types.PrimitiveType;
30
import mockit.asm.types.ReferenceType;
31
import mockit.asm.util.ByteVector;
32
import mockit.asm.util.MethodHandle;
33
import mockit.internal.util.ClassLoad;
34

35
import org.checkerframework.checker.index.qual.NonNegative;
36

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

49
    /**
50
     * The constant pool's hash table data.
51
     */
52
    @NonNull
53
    private Item[] items;
54

55
    /**
56
     * The threshold of the constant pool's hash table.
57
     */
58
    @NonNegative
59
    private int threshold;
60

61
    /**
62
     * Index of the next item to be added in the constant pool.
63
     */
64
    @NonNegative
65
    private int index;
66

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

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

99
    /**
100
     * Number of elements in the {@link #typeTable} array.
101
     */
102
    private short typeCount;
103

104
    @NonNull
105
    private final NormalTypeTableItem reusableNormalItem;
106
    @NonNull
107
    private final UninitializedTypeTableItem reusableUninitializedItem;
108
    @NonNull
109
    private final MergedTypeTableItem reusableMergedItem;
110

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

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

146
        StringItem result = get(reusableUTF8Item);
1✔
147

148
        if (result == null) {
1✔
149
            pool.putByte(UTF8).putUTF8(value);
1✔
150

151
            result = new StringItem(index++, reusableUTF8Item);
1✔
152
            put(result);
1✔
153
        }
154

155
        return result.index;
1✔
156
    }
157

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

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

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

202
        StringItem result = get(reusableStringItem);
1✔
203

204
        if (result == null) {
1✔
205
            int itemIndex = newUTF8(value);
1✔
206
            pool.put12(type, itemIndex);
1✔
207

208
            result = new StringItem(index++, reusableStringItem);
1✔
209
            put(result);
1✔
210
        }
211

212
        return result;
1✔
213
    }
214

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

225
        MethodHandleItem result = get(reusableMethodHandleItem);
1✔
226

227
        if (result == null) {
1!
228
            int tag = methodHandle.tag;
×
229
            int memberType = tag == MethodHandle.Tag.TAG_INVOKEINTERFACE ? IMETHOD_REF : METHOD_REF;
×
230
            ClassMemberItem memberItem = newClassMemberItem(memberType, methodHandle.owner, methodHandle.name,
×
231
                    methodHandle.desc);
232
            pool.put11(METHOD_HANDLE, tag).putShort(memberItem.index);
×
233

234
            result = new MethodHandleItem(index++, reusableMethodHandleItem);
×
235
            put(result);
×
236
        }
237

238
        return result;
1✔
239
    }
240

241
    @NonNull
242
    private ClassMemberItem newClassMemberItem(int type, @NonNull String owner, @NonNull String name,
243
            @NonNull String desc) {
244
        reusableClassMemberItem.set(type, owner, name, desc);
1✔
245

246
        ClassMemberItem result = get(reusableClassMemberItem);
1✔
247

248
        if (result == null) {
1✔
249
            int ownerItemIndex = newClass(owner);
1✔
250
            int nameAndTypeItemIndex = newNameType(name, desc);
1✔
251
            put122(type, ownerItemIndex, nameAndTypeItemIndex);
1✔
252

253
            result = new ClassMemberItem(index++, reusableClassMemberItem);
1✔
254
            put(result);
1✔
255
        }
256

257
        return result;
1✔
258
    }
259

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

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

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

312
        IntItem result = get(reusableIntItem);
1✔
313

314
        if (result == null) {
1✔
315
            pool.putByte(INTEGER).putInt(value);
1✔
316

317
            result = new IntItem(index++, reusableIntItem);
1✔
318
            put(result);
1✔
319
        }
320

321
        return result;
1✔
322
    }
323

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

337
        FloatItem result = get(reusableFloatItem);
1✔
338

339
        if (result == null) {
1!
340
            pool.putByte(FLOAT).putInt(reusableFloatItem.intVal);
×
341

342
            result = new FloatItem(index++, reusableFloatItem);
×
343
            put(result);
×
344
        }
345

346
        return result;
1✔
347
    }
348

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

362
        LongItem result = get(reusableLongItem);
1✔
363

364
        if (result == null) {
1!
365
            pool.putByte(LONG).putLong(value);
×
366

367
            result = new LongItem(index, reusableLongItem);
×
368
            index += 2;
×
369
            put(result);
×
370
        }
371

372
        return result;
1✔
373
    }
374

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

388
        DoubleItem result = get(reusableDoubleItem);
1✔
389

390
        if (result == null) {
1!
391
            pool.putByte(DOUBLE).putLong(reusableDoubleItem.longVal);
×
392

393
            result = new DoubleItem(index, reusableDoubleItem);
×
394
            index += 2;
×
395
            put(result);
×
396
        }
397

398
        return result;
1✔
399
    }
400

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

416
        NameAndTypeItem result = get(reusableNameTypeItem);
1✔
417

418
        if (result == null) {
1✔
419
            int nameItemIndex = newUTF8(name);
1✔
420
            int descItemIndex = newUTF8(desc);
1✔
421
            put122(NAME_TYPE, nameItemIndex, descItemIndex);
1✔
422

423
            result = new NameAndTypeItem(index++, reusableNameTypeItem);
1✔
424
            put(result);
1✔
425
        }
426

427
        return result.index;
1✔
428
    }
429

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

446
        if (cst instanceof Number) {
1✔
447
            return newNumberItem((Number) cst);
1✔
448
        }
449

450
        if (cst instanceof Character) {
1!
451
            return newInteger((Character) cst);
×
452
        }
453

454
        if (cst instanceof Boolean) {
1!
455
            int val = (boolean) cst ? 1 : 0;
×
456
            return newInteger(val);
×
457
        }
458

459
        if (cst instanceof ReferenceType) {
1✔
460
            String typeDesc = ((ReferenceType) cst).getInternalName();
1✔
461
            return cst instanceof MethodType ? newStringItem(METHOD_TYPE, typeDesc) : newClassItem(typeDesc);
1✔
462
        }
463

464
        if (cst instanceof PrimitiveType) {
1!
465
            String typeDesc = ((PrimitiveType) cst).getDescriptor();
×
466
            return newClassItem(typeDesc);
×
467
        }
468

469
        if (cst instanceof MethodHandle) {
1✔
470
            return newMethodHandleItem((MethodHandle) cst);
1✔
471
        }
472

473
        if (cst instanceof DynamicItem) {
1!
474
            DynamicItem dynamicItem = (DynamicItem) cst;
1✔
475
            return createDynamicItem(dynamicItem.type, dynamicItem.name, dynamicItem.desc, dynamicItem.bsmIndex);
1✔
476
        }
477
        throw new IllegalArgumentException("value " + cst);
×
478
    }
479

480
    @NonNull
481
    private Item newNumberItem(@NonNull Number cst) {
482
        if (cst instanceof Float) {
1✔
483
            return newFloat(cst.floatValue());
1✔
484
        }
485

486
        if (cst instanceof Long) {
1✔
487
            return newLong(cst.longValue());
1✔
488
        }
489

490
        if (cst instanceof Double) {
1✔
491
            return newDouble(cst.doubleValue());
1✔
492
        }
493

494
        return newInteger(cst.intValue());
1✔
495
    }
496

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

510
        TypeTableItem result = get(reusableNormalItem);
1✔
511

512
        if (result == null) {
1✔
513
            result = new NormalTypeTableItem(++typeCount, reusableNormalItem);
1✔
514
            addToTypeTable(result);
1✔
515
        }
516

517
        return result.index;
1✔
518
    }
519

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

535
        TypeTableItem result = get(reusableUninitializedItem);
1✔
536

537
        if (result == null) {
1✔
538
            result = new UninitializedTypeTableItem(++typeCount, reusableUninitializedItem);
1✔
539
            addToTypeTable(result);
1✔
540
        }
541

542
        return result.index;
1✔
543
    }
544

545
    private void addToTypeTable(@NonNull TypeTableItem newItem) {
546
        put(newItem);
1✔
547

548
        if (typeTable == null) {
1✔
549
            typeTable = new TypeTableItem[16];
1✔
550
        }
551

552
        int newItemIndex = typeCount;
1✔
553
        enlargeTypeTableIfNeeded(newItemIndex);
1✔
554
        typeTable[newItemIndex] = newItem;
1✔
555
    }
1✔
556

557
    private void enlargeTypeTableIfNeeded(@NonNegative int newItemIndex) {
558
        int currentTypeCount = typeTable.length;
1✔
559

560
        if (newItemIndex == currentTypeCount) {
1✔
561
            TypeTableItem[] newTable = new TypeTableItem[2 * currentTypeCount];
1✔
562
            System.arraycopy(typeTable, 0, newTable, 0, currentTypeCount);
1✔
563
            typeTable = newTable;
1✔
564
        }
565
    }
1✔
566

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

582
        MergedTypeTableItem result = get(reusableMergedItem);
1✔
583

584
        if (result == null) {
1✔
585
            String type1Desc = getInternalName(type1);
1✔
586
            String type2Desc = getInternalName(type2);
1✔
587
            String commonSuperClass = getCommonSuperClass(type1Desc, type2Desc);
1✔
588
            reusableMergedItem.commonSuperTypeIndex = addNormalType(commonSuperClass);
1✔
589

590
            result = new MergedTypeTableItem(reusableMergedItem);
1✔
591
            put(result);
1✔
592
        }
593

594
        return result.commonSuperTypeIndex;
1✔
595
    }
596

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

617
        while (true) {
618
            if (OBJECT.equals(class1) || OBJECT.equals(class2)) {
1✔
619
                return OBJECT;
1✔
620
            }
621

622
            String superClass = ClassLoad.whichIsSuperClass(class1, class2);
1✔
623

624
            if (superClass != null) {
1✔
625
                return superClass;
1✔
626
            }
627

628
            class1 = ClassLoad.getSuperClass(class1);
1✔
629
            class2 = ClassLoad.getSuperClass(class2);
1✔
630

631
            if (class1.equals(class2)) {
1✔
632
                return class1;
1✔
633
            }
634
        }
1✔
635
    }
636

637
    @NonNull
638
    public String getInternalName(@NonNegative int typeTableIndex) {
639
        TypeTableItem typeTableItem = typeTable[typeTableIndex]; // Normal or Uninitialized
1✔
640
        return typeTableItem.typeDesc;
1✔
641
    }
642

643
    @NonNull
644
    public UninitializedTypeTableItem getUninitializedItemValue(@NonNegative int typeTableIndex) {
645
        return (UninitializedTypeTableItem) typeTable[typeTableIndex];
1✔
646
    }
647

648
    @Nullable
649
    public Item getItem(@NonNegative int itemHashCode) {
650
        return items[itemHashCode % items.length];
1✔
651
    }
652

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

667
        while (item != null && (item.getType() != keyType || !key.isEqualTo(item))) {
1✔
668
            item = item.getNext();
1✔
669
        }
670

671
        // noinspection unchecked
672
        return (I) item;
1✔
673
    }
674

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

686
    private void resizeItemArrayIfNeeded() {
687
        if (index + typeCount > threshold) {
1✔
688
            int ll = items.length;
1✔
689
            int nl = ll * 2 + 1;
1✔
690
            Item[] newItems = new Item[nl];
1✔
691

692
            for (int l = ll - 1; l >= 0; l--) {
1✔
693
                Item j = items[l];
1✔
694
                put(newItems, j);
1✔
695
            }
696

697
            items = newItems;
1✔
698
            // noinspection NumericCastThatLosesPrecision
699
            threshold = (int) (nl * 0.75);
1✔
700
        }
701
    }
1✔
702

703
    private static void put(@NonNull Item[] newItems, @Nullable Item item) {
704
        while (item != null) {
1✔
705
            Item next = item.getNext();
1✔
706
            item.setNext(newItems);
1✔
707
            // noinspection AssignmentToMethodParameter
708
            item = next;
1✔
709
        }
1✔
710
    }
1✔
711

712
    /**
713
     * Puts one byte and two shorts into the constant pool.
714
     */
715
    private void put122(int b, int s1, int s2) {
716
        pool.put12(b, s1).putShort(s2);
1✔
717
    }
1✔
718

719
    @NonNegative
720
    public int getSize() {
721
        return pool.getLength();
1✔
722
    }
723

724
    public void checkConstantPoolMaxSize() {
725
        if (index > 0xFFFF) {
1!
726
            throw new RuntimeException("Class file too large!");
×
727
        }
728
    }
1✔
729

730
    public void put(@NonNull ByteVector out) {
731
        out.putShort(index).putByteVector(pool);
1✔
732
    }
1✔
733

734
    public void copy(@NonNull byte[] code, @NonNegative int off, @NonNegative int header, @NonNull Item[] cpItems) {
735
        pool.putByteArray(code, off, header - off);
1✔
736
        items = cpItems;
1✔
737

738
        int ll = cpItems.length;
1✔
739
        // noinspection NumericCastThatLosesPrecision
740
        threshold = (int) (0.75d * ll);
1✔
741
        index = ll;
1✔
742
    }
1✔
743

744
    @NonNull
745
    public DynamicItem createDynamicItem(int type, @NonNull String name, @NonNull String desc,
746
            @NonNegative int bsmIndex) {
747
        reusableDynamicItem.set(type, name, desc, bsmIndex);
1✔
748

749
        DynamicItem result = get(reusableDynamicItem);
1✔
750

751
        if (result == null) {
1!
752
            int nameAndTypeItemIndex = newNameType(name, desc);
×
753
            put122(type, bsmIndex, nameAndTypeItemIndex);
×
754

755
            result = new DynamicItem(index++, reusableDynamicItem);
×
756
            put(result);
×
757
        }
758

759
        return result;
1✔
760
    }
761
}
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