• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm;
29 
30 /**
31  * The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
32  * table entries of a class.
33  *
34  * @author Eric Bruneton
35  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
36  *     4.4</a>
37  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
38  *     4.7.23</a>
39  */
40 final class SymbolTable {
41 
42   /**
43    * The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link
44    * ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link
45    * Attribute#write}.
46    */
47   final ClassWriter classWriter;
48 
49   /**
50    * The ClassReader from which this SymbolTable was constructed, or {@literal null} if it was
51    * constructed from scratch.
52    */
53   private final ClassReader sourceClassReader;
54 
55   /** The major version number of the class to which this symbol table belongs. */
56   private int majorVersion;
57 
58   /** The internal name of the class to which this symbol table belongs. */
59   private String className;
60 
61   /**
62    * The total number of {@link Entry} instances in {@link #entries}. This includes entries that are
63    * accessible (recursively) via {@link Entry#next}.
64    */
65   private int entryCount;
66 
67   /**
68    * A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the
69    * bootstrap method entries and the type table entries). Each {@link Entry} instance is stored at
70    * the array index given by its hash code modulo the array size. If several entries must be stored
71    * at the same array index, they are linked together via their {@link Entry#next} field. The
72    * factory methods of this class make sure that this table does not contain duplicated entries.
73    */
74   private Entry[] entries;
75 
76   /**
77    * The number of constant pool items in {@link #constantPool}, plus 1. The first constant pool
78    * item has index 1, and long and double items count for two items.
79    */
80   private int constantPoolCount;
81 
82   /**
83    * The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable.
84    * The ClassFile's constant_pool_count field is <i>not</i> included.
85    */
86   private ByteVector constantPool;
87 
88   /**
89    * The number of bootstrap methods in {@link #bootstrapMethods}. Corresponds to the
90    * BootstrapMethods_attribute's num_bootstrap_methods field value.
91    */
92   private int bootstrapMethodCount;
93 
94   /**
95    * The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this
96    * SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its
97    * num_bootstrap_methods field, are <i>not</i> included.
98    */
99   private ByteVector bootstrapMethods;
100 
101   /**
102    * The actual number of elements in {@link #typeTable}. These elements are stored from index 0 to
103    * typeCount (excluded). The other array entries are empty.
104    */
105   private int typeCount;
106 
107   /**
108    * An ASM specific type table used to temporarily store internal names that will not necessarily
109    * be stored in the constant pool. This type table is used by the control flow and data flow
110    * analysis algorithm used to compute stack map frames from scratch. This array stores {@link
111    * Symbol#TYPE_TAG} and {@link Symbol#UNINITIALIZED_TYPE_TAG}) Symbol. The type symbol at index
112    * {@code i} has its {@link Symbol#index} equal to {@code i} (and vice versa).
113    */
114   private Entry[] typeTable;
115 
116   /**
117    * Constructs a new, empty SymbolTable for the given ClassWriter.
118    *
119    * @param classWriter a ClassWriter.
120    */
SymbolTable(final ClassWriter classWriter)121   SymbolTable(final ClassWriter classWriter) {
122     this.classWriter = classWriter;
123     this.sourceClassReader = null;
124     this.entries = new Entry[256];
125     this.constantPoolCount = 1;
126     this.constantPool = new ByteVector();
127   }
128 
129   /**
130    * Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and
131    * bootstrap methods of the given ClassReader.
132    *
133    * @param classWriter a ClassWriter.
134    * @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to
135    *     initialize the SymbolTable.
136    */
SymbolTable(final ClassWriter classWriter, final ClassReader classReader)137   SymbolTable(final ClassWriter classWriter, final ClassReader classReader) {
138     this.classWriter = classWriter;
139     this.sourceClassReader = classReader;
140 
141     // Copy the constant pool binary content.
142     byte[] inputBytes = classReader.classFileBuffer;
143     int constantPoolOffset = classReader.getItem(1) - 1;
144     int constantPoolLength = classReader.header - constantPoolOffset;
145     constantPoolCount = classReader.getItemCount();
146     constantPool = new ByteVector(constantPoolLength);
147     constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength);
148 
149     // Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to
150     // avoid too many hash set collisions (entries is not dynamically resized by the addConstant*
151     // method calls below), and to account for bootstrap method entries.
152     entries = new Entry[constantPoolCount * 2];
153     char[] charBuffer = new char[classReader.getMaxStringLength()];
154     boolean hasBootstrapMethods = false;
155     int itemIndex = 1;
156     while (itemIndex < constantPoolCount) {
157       int itemOffset = classReader.getItem(itemIndex);
158       int itemTag = inputBytes[itemOffset - 1];
159       int nameAndTypeItemOffset;
160       switch (itemTag) {
161         case Symbol.CONSTANT_FIELDREF_TAG:
162         case Symbol.CONSTANT_METHODREF_TAG:
163         case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
164           nameAndTypeItemOffset =
165               classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
166           addConstantMemberReference(
167               itemIndex,
168               itemTag,
169               classReader.readClass(itemOffset, charBuffer),
170               classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
171               classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
172           break;
173         case Symbol.CONSTANT_INTEGER_TAG:
174         case Symbol.CONSTANT_FLOAT_TAG:
175           addConstantIntegerOrFloat(itemIndex, itemTag, classReader.readInt(itemOffset));
176           break;
177         case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
178           addConstantNameAndType(
179               itemIndex,
180               classReader.readUTF8(itemOffset, charBuffer),
181               classReader.readUTF8(itemOffset + 2, charBuffer));
182           break;
183         case Symbol.CONSTANT_LONG_TAG:
184         case Symbol.CONSTANT_DOUBLE_TAG:
185           addConstantLongOrDouble(itemIndex, itemTag, classReader.readLong(itemOffset));
186           break;
187         case Symbol.CONSTANT_UTF8_TAG:
188           addConstantUtf8(itemIndex, classReader.readUtf(itemIndex, charBuffer));
189           break;
190         case Symbol.CONSTANT_METHOD_HANDLE_TAG:
191           int memberRefItemOffset =
192               classReader.getItem(classReader.readUnsignedShort(itemOffset + 1));
193           nameAndTypeItemOffset =
194               classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2));
195           addConstantMethodHandle(
196               itemIndex,
197               classReader.readByte(itemOffset),
198               classReader.readClass(memberRefItemOffset, charBuffer),
199               classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
200               classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
201           break;
202         case Symbol.CONSTANT_DYNAMIC_TAG:
203         case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
204           hasBootstrapMethods = true;
205           nameAndTypeItemOffset =
206               classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
207           addConstantDynamicOrInvokeDynamicReference(
208               itemTag,
209               itemIndex,
210               classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
211               classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer),
212               classReader.readUnsignedShort(itemOffset));
213           break;
214         case Symbol.CONSTANT_STRING_TAG:
215         case Symbol.CONSTANT_CLASS_TAG:
216         case Symbol.CONSTANT_METHOD_TYPE_TAG:
217         case Symbol.CONSTANT_MODULE_TAG:
218         case Symbol.CONSTANT_PACKAGE_TAG:
219           addConstantUtf8Reference(
220               itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer));
221           break;
222         default:
223           throw new IllegalArgumentException();
224       }
225       itemIndex +=
226           (itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1;
227     }
228 
229     // Copy the BootstrapMethods, if any.
230     if (hasBootstrapMethods) {
231       copyBootstrapMethods(classReader, charBuffer);
232     }
233   }
234 
235   /**
236    * Read the BootstrapMethods 'bootstrap_methods' array binary content and add them as entries of
237    * the SymbolTable.
238    *
239    * @param classReader the ClassReader whose bootstrap methods must be copied to initialize the
240    *     SymbolTable.
241    * @param charBuffer a buffer used to read strings in the constant pool.
242    */
copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer)243   private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) {
244     // Find attributOffset of the 'bootstrap_methods' array.
245     byte[] inputBytes = classReader.classFileBuffer;
246     int currentAttributeOffset = classReader.getFirstAttributeOffset();
247     for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
248       String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
249       if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
250         bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6);
251         break;
252       }
253       currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2);
254     }
255     if (bootstrapMethodCount > 0) {
256       // Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array.
257       int bootstrapMethodsOffset = currentAttributeOffset + 8;
258       int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2;
259       bootstrapMethods = new ByteVector(bootstrapMethodsLength);
260       bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength);
261 
262       // Add each bootstrap method in the symbol table entries.
263       int currentOffset = bootstrapMethodsOffset;
264       for (int i = 0; i < bootstrapMethodCount; i++) {
265         int offset = currentOffset - bootstrapMethodsOffset;
266         int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset);
267         currentOffset += 2;
268         int numBootstrapArguments = classReader.readUnsignedShort(currentOffset);
269         currentOffset += 2;
270         int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode();
271         while (numBootstrapArguments-- > 0) {
272           int bootstrapArgument = classReader.readUnsignedShort(currentOffset);
273           currentOffset += 2;
274           hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode();
275         }
276         add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF));
277       }
278     }
279   }
280 
281   /**
282    * Returns the ClassReader from which this SymbolTable was constructed.
283    *
284    * @return the ClassReader from which this SymbolTable was constructed, or {@literal null} if it
285    *     was constructed from scratch.
286    */
getSource()287   ClassReader getSource() {
288     return sourceClassReader;
289   }
290 
291   /**
292    * Returns the major version of the class to which this symbol table belongs.
293    *
294    * @return the major version of the class to which this symbol table belongs.
295    */
getMajorVersion()296   int getMajorVersion() {
297     return majorVersion;
298   }
299 
300   /**
301    * Returns the internal name of the class to which this symbol table belongs.
302    *
303    * @return the internal name of the class to which this symbol table belongs.
304    */
getClassName()305   String getClassName() {
306     return className;
307   }
308 
309   /**
310    * Sets the major version and the name of the class to which this symbol table belongs. Also adds
311    * the class name to the constant pool.
312    *
313    * @param majorVersion a major ClassFile version number.
314    * @param className an internal class name.
315    * @return the constant pool index of a new or already existing Symbol with the given class name.
316    */
setMajorVersionAndClassName(final int majorVersion, final String className)317   int setMajorVersionAndClassName(final int majorVersion, final String className) {
318     this.majorVersion = majorVersion;
319     this.className = className;
320     return addConstantClass(className).index;
321   }
322 
323   /**
324    * Returns the number of items in this symbol table's constant_pool array (plus 1).
325    *
326    * @return the number of items in this symbol table's constant_pool array (plus 1).
327    */
getConstantPoolCount()328   int getConstantPoolCount() {
329     return constantPoolCount;
330   }
331 
332   /**
333    * Returns the length in bytes of this symbol table's constant_pool array.
334    *
335    * @return the length in bytes of this symbol table's constant_pool array.
336    */
getConstantPoolLength()337   int getConstantPoolLength() {
338     return constantPool.length;
339   }
340 
341   /**
342    * Puts this symbol table's constant_pool array in the given ByteVector, preceded by the
343    * constant_pool_count value.
344    *
345    * @param output where the JVMS ClassFile's constant_pool array must be put.
346    */
putConstantPool(final ByteVector output)347   void putConstantPool(final ByteVector output) {
348     output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length);
349   }
350 
351   /**
352    * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the
353    * attribute name in the constant pool.
354    *
355    * @return the size in bytes of this symbol table's BootstrapMethods attribute.
356    */
computeBootstrapMethodsSize()357   int computeBootstrapMethodsSize() {
358     if (bootstrapMethods != null) {
359       addConstantUtf8(Constants.BOOTSTRAP_METHODS);
360       return 8 + bootstrapMethods.length;
361     } else {
362       return 0;
363     }
364   }
365 
366   /**
367    * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the
368    * 6 attribute header bytes and the num_bootstrap_methods value.
369    *
370    * @param output where the JVMS BootstrapMethods attribute must be put.
371    */
putBootstrapMethods(final ByteVector output)372   void putBootstrapMethods(final ByteVector output) {
373     if (bootstrapMethods != null) {
374       output
375           .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS))
376           .putInt(bootstrapMethods.length + 2)
377           .putShort(bootstrapMethodCount)
378           .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
379     }
380   }
381 
382   // -----------------------------------------------------------------------------------------------
383   // Generic symbol table entries management.
384   // -----------------------------------------------------------------------------------------------
385 
386   /**
387    * Returns the list of entries which can potentially have the given hash code.
388    *
389    * @param hashCode a {@link Entry#hashCode} value.
390    * @return the list of entries which can potentially have the given hash code. The list is stored
391    *     via the {@link Entry#next} field.
392    */
get(final int hashCode)393   private Entry get(final int hashCode) {
394     return entries[hashCode % entries.length];
395   }
396 
397   /**
398    * Puts the given entry in the {@link #entries} hash set. This method does <i>not</i> check
399    * whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized
400    * if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link
401    * #entries} array index) as much as possible, with reasonable memory usage.
402    *
403    * @param entry an Entry (which must not already be contained in {@link #entries}).
404    * @return the given entry
405    */
put(final Entry entry)406   private Entry put(final Entry entry) {
407     if (entryCount > (entries.length * 3) / 4) {
408       int currentCapacity = entries.length;
409       int newCapacity = currentCapacity * 2 + 1;
410       Entry[] newEntries = new Entry[newCapacity];
411       for (int i = currentCapacity - 1; i >= 0; --i) {
412         Entry currentEntry = entries[i];
413         while (currentEntry != null) {
414           int newCurrentEntryIndex = currentEntry.hashCode % newCapacity;
415           Entry nextEntry = currentEntry.next;
416           currentEntry.next = newEntries[newCurrentEntryIndex];
417           newEntries[newCurrentEntryIndex] = currentEntry;
418           currentEntry = nextEntry;
419         }
420       }
421       entries = newEntries;
422     }
423     entryCount++;
424     int index = entry.hashCode % entries.length;
425     entry.next = entries[index];
426     return entries[index] = entry;
427   }
428 
429   /**
430    * Adds the given entry in the {@link #entries} hash set. This method does <i>not</i> check
431    * whether {@link #entries} already contains a similar entry or not, and does <i>not</i> resize
432    * {@link #entries} if necessary.
433    *
434    * @param entry an Entry (which must not already be contained in {@link #entries}).
435    */
add(final Entry entry)436   private void add(final Entry entry) {
437     entryCount++;
438     int index = entry.hashCode % entries.length;
439     entry.next = entries[index];
440     entries[index] = entry;
441   }
442 
443   // -----------------------------------------------------------------------------------------------
444   // Constant pool entries management.
445   // -----------------------------------------------------------------------------------------------
446 
447   /**
448    * Adds a number or string constant to the constant pool of this symbol table. Does nothing if the
449    * constant pool already contains a similar item.
450    *
451    * @param value the value of the constant to be added to the constant pool. This parameter must be
452    *     an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link
453    *     Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}.
454    * @return a new or already existing Symbol with the given value.
455    */
addConstant(final Object value)456   Symbol addConstant(final Object value) {
457     if (value instanceof Integer) {
458       return addConstantInteger(((Integer) value).intValue());
459     } else if (value instanceof Byte) {
460       return addConstantInteger(((Byte) value).intValue());
461     } else if (value instanceof Character) {
462       return addConstantInteger(((Character) value).charValue());
463     } else if (value instanceof Short) {
464       return addConstantInteger(((Short) value).intValue());
465     } else if (value instanceof Boolean) {
466       return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0);
467     } else if (value instanceof Float) {
468       return addConstantFloat(((Float) value).floatValue());
469     } else if (value instanceof Long) {
470       return addConstantLong(((Long) value).longValue());
471     } else if (value instanceof Double) {
472       return addConstantDouble(((Double) value).doubleValue());
473     } else if (value instanceof String) {
474       return addConstantString((String) value);
475     } else if (value instanceof Type) {
476       Type type = (Type) value;
477       int typeSort = type.getSort();
478       if (typeSort == Type.OBJECT) {
479         return addConstantClass(type.getInternalName());
480       } else if (typeSort == Type.METHOD) {
481         return addConstantMethodType(type.getDescriptor());
482       } else { // type is a primitive or array type.
483         return addConstantClass(type.getDescriptor());
484       }
485     } else if (value instanceof Handle) {
486       Handle handle = (Handle) value;
487       return addConstantMethodHandle(
488           handle.getTag(),
489           handle.getOwner(),
490           handle.getName(),
491           handle.getDesc(),
492           handle.isInterface());
493     } else if (value instanceof ConstantDynamic) {
494       ConstantDynamic constantDynamic = (ConstantDynamic) value;
495       return addConstantDynamic(
496           constantDynamic.getName(),
497           constantDynamic.getDescriptor(),
498           constantDynamic.getBootstrapMethod(),
499           constantDynamic.getBootstrapMethodArgumentsUnsafe());
500     } else {
501       throw new IllegalArgumentException("value " + value);
502     }
503   }
504 
505   /**
506    * Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the
507    * constant pool already contains a similar item.
508    *
509    * @param value the internal name of a class.
510    * @return a new or already existing Symbol with the given value.
511    */
addConstantClass(final String value)512   Symbol addConstantClass(final String value) {
513     return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value);
514   }
515 
516   /**
517    * Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the
518    * constant pool already contains a similar item.
519    *
520    * @param owner the internal name of a class.
521    * @param name a field name.
522    * @param descriptor a field descriptor.
523    * @return a new or already existing Symbol with the given value.
524    */
addConstantFieldref(final String owner, final String name, final String descriptor)525   Symbol addConstantFieldref(final String owner, final String name, final String descriptor) {
526     return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor);
527   }
528 
529   /**
530    * Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this
531    * symbol table. Does nothing if the constant pool already contains a similar item.
532    *
533    * @param owner the internal name of a class.
534    * @param name a method name.
535    * @param descriptor a method descriptor.
536    * @param isInterface whether owner is an interface or not.
537    * @return a new or already existing Symbol with the given value.
538    */
addConstantMethodref( final String owner, final String name, final String descriptor, final boolean isInterface)539   Symbol addConstantMethodref(
540       final String owner, final String name, final String descriptor, final boolean isInterface) {
541     int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG;
542     return addConstantMemberReference(tag, owner, name, descriptor);
543   }
544 
545   /**
546    * Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to
547    * the constant pool of this symbol table. Does nothing if the constant pool already contains a
548    * similar item.
549    *
550    * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
551    *     or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
552    * @param owner the internal name of a class.
553    * @param name a field or method name.
554    * @param descriptor a field or method descriptor.
555    * @return a new or already existing Symbol with the given value.
556    */
addConstantMemberReference( final int tag, final String owner, final String name, final String descriptor)557   private Entry addConstantMemberReference(
558       final int tag, final String owner, final String name, final String descriptor) {
559     int hashCode = hash(tag, owner, name, descriptor);
560     Entry entry = get(hashCode);
561     while (entry != null) {
562       if (entry.tag == tag
563           && entry.hashCode == hashCode
564           && entry.owner.equals(owner)
565           && entry.name.equals(name)
566           && entry.value.equals(descriptor)) {
567         return entry;
568       }
569       entry = entry.next;
570     }
571     constantPool.put122(
572         tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor));
573     return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode));
574   }
575 
576   /**
577    * Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info
578    * to the constant pool of this symbol table.
579    *
580    * @param index the constant pool index of the new Symbol.
581    * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
582    *     or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
583    * @param owner the internal name of a class.
584    * @param name a field or method name.
585    * @param descriptor a field or method descriptor.
586    */
addConstantMemberReference( final int index, final int tag, final String owner, final String name, final String descriptor)587   private void addConstantMemberReference(
588       final int index,
589       final int tag,
590       final String owner,
591       final String name,
592       final String descriptor) {
593     add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor)));
594   }
595 
596   /**
597    * Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the
598    * constant pool already contains a similar item.
599    *
600    * @param value a string.
601    * @return a new or already existing Symbol with the given value.
602    */
addConstantString(final String value)603   Symbol addConstantString(final String value) {
604     return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value);
605   }
606 
607   /**
608    * Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the
609    * constant pool already contains a similar item.
610    *
611    * @param value an int.
612    * @return a new or already existing Symbol with the given value.
613    */
addConstantInteger(final int value)614   Symbol addConstantInteger(final int value) {
615     return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, value);
616   }
617 
618   /**
619    * Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the
620    * constant pool already contains a similar item.
621    *
622    * @param value a float.
623    * @return a new or already existing Symbol with the given value.
624    */
addConstantFloat(final float value)625   Symbol addConstantFloat(final float value) {
626     return addConstantIntegerOrFloat(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value));
627   }
628 
629   /**
630    * Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table.
631    * Does nothing if the constant pool already contains a similar item.
632    *
633    * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
634    * @param value an int or float.
635    * @return a constant pool constant with the given tag and primitive values.
636    */
addConstantIntegerOrFloat(final int tag, final int value)637   private Symbol addConstantIntegerOrFloat(final int tag, final int value) {
638     int hashCode = hash(tag, value);
639     Entry entry = get(hashCode);
640     while (entry != null) {
641       if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
642         return entry;
643       }
644       entry = entry.next;
645     }
646     constantPool.putByte(tag).putInt(value);
647     return put(new Entry(constantPoolCount++, tag, value, hashCode));
648   }
649 
650   /**
651    * Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol
652    * table.
653    *
654    * @param index the constant pool index of the new Symbol.
655    * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
656    * @param value an int or float.
657    */
addConstantIntegerOrFloat(final int index, final int tag, final int value)658   private void addConstantIntegerOrFloat(final int index, final int tag, final int value) {
659     add(new Entry(index, tag, value, hash(tag, value)));
660   }
661 
662   /**
663    * Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the
664    * constant pool already contains a similar item.
665    *
666    * @param value a long.
667    * @return a new or already existing Symbol with the given value.
668    */
addConstantLong(final long value)669   Symbol addConstantLong(final long value) {
670     return addConstantLongOrDouble(Symbol.CONSTANT_LONG_TAG, value);
671   }
672 
673   /**
674    * Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the
675    * constant pool already contains a similar item.
676    *
677    * @param value a double.
678    * @return a new or already existing Symbol with the given value.
679    */
addConstantDouble(final double value)680   Symbol addConstantDouble(final double value) {
681     return addConstantLongOrDouble(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value));
682   }
683 
684   /**
685    * Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table.
686    * Does nothing if the constant pool already contains a similar item.
687    *
688    * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
689    * @param value a long or double.
690    * @return a constant pool constant with the given tag and primitive values.
691    */
addConstantLongOrDouble(final int tag, final long value)692   private Symbol addConstantLongOrDouble(final int tag, final long value) {
693     int hashCode = hash(tag, value);
694     Entry entry = get(hashCode);
695     while (entry != null) {
696       if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
697         return entry;
698       }
699       entry = entry.next;
700     }
701     int index = constantPoolCount;
702     constantPool.putByte(tag).putLong(value);
703     constantPoolCount += 2;
704     return put(new Entry(index, tag, value, hashCode));
705   }
706 
707   /**
708    * Adds a new CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol
709    * table.
710    *
711    * @param index the constant pool index of the new Symbol.
712    * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
713    * @param value a long or double.
714    */
addConstantLongOrDouble(final int index, final int tag, final long value)715   private void addConstantLongOrDouble(final int index, final int tag, final long value) {
716     add(new Entry(index, tag, value, hash(tag, value)));
717   }
718 
719   /**
720    * Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the
721    * constant pool already contains a similar item.
722    *
723    * @param name a field or method name.
724    * @param descriptor a field or method descriptor.
725    * @return a new or already existing Symbol with the given value.
726    */
addConstantNameAndType(final String name, final String descriptor)727   int addConstantNameAndType(final String name, final String descriptor) {
728     final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
729     int hashCode = hash(tag, name, descriptor);
730     Entry entry = get(hashCode);
731     while (entry != null) {
732       if (entry.tag == tag
733           && entry.hashCode == hashCode
734           && entry.name.equals(name)
735           && entry.value.equals(descriptor)) {
736         return entry.index;
737       }
738       entry = entry.next;
739     }
740     constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor));
741     return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index;
742   }
743 
744   /**
745    * Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table.
746    *
747    * @param index the constant pool index of the new Symbol.
748    * @param name a field or method name.
749    * @param descriptor a field or method descriptor.
750    */
addConstantNameAndType(final int index, final String name, final String descriptor)751   private void addConstantNameAndType(final int index, final String name, final String descriptor) {
752     final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
753     add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor)));
754   }
755 
756   /**
757    * Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the
758    * constant pool already contains a similar item.
759    *
760    * @param value a string.
761    * @return a new or already existing Symbol with the given value.
762    */
addConstantUtf8(final String value)763   int addConstantUtf8(final String value) {
764     int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value);
765     Entry entry = get(hashCode);
766     while (entry != null) {
767       if (entry.tag == Symbol.CONSTANT_UTF8_TAG
768           && entry.hashCode == hashCode
769           && entry.value.equals(value)) {
770         return entry.index;
771       }
772       entry = entry.next;
773     }
774     constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value);
775     return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index;
776   }
777 
778   /**
779    * Adds a new CONSTANT_String_info to the constant pool of this symbol table.
780    *
781    * @param index the constant pool index of the new Symbol.
782    * @param value a string.
783    */
addConstantUtf8(final int index, final String value)784   private void addConstantUtf8(final int index, final String value) {
785     add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value)));
786   }
787 
788   /**
789    * Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if
790    * the constant pool already contains a similar item.
791    *
792    * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
793    *     Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
794    *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
795    *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
796    * @param owner the internal name of a class of interface.
797    * @param name a field or method name.
798    * @param descriptor a field or method descriptor.
799    * @param isInterface whether owner is an interface or not.
800    * @return a new or already existing Symbol with the given value.
801    */
addConstantMethodHandle( final int referenceKind, final String owner, final String name, final String descriptor, final boolean isInterface)802   Symbol addConstantMethodHandle(
803       final int referenceKind,
804       final String owner,
805       final String name,
806       final String descriptor,
807       final boolean isInterface) {
808     final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
809     // Note that we don't need to include isInterface in the hash computation, because it is
810     // redundant with owner (we can't have the same owner with different isInterface values).
811     int hashCode = hash(tag, owner, name, descriptor, referenceKind);
812     Entry entry = get(hashCode);
813     while (entry != null) {
814       if (entry.tag == tag
815           && entry.hashCode == hashCode
816           && entry.data == referenceKind
817           && entry.owner.equals(owner)
818           && entry.name.equals(name)
819           && entry.value.equals(descriptor)) {
820         return entry;
821       }
822       entry = entry.next;
823     }
824     if (referenceKind <= Opcodes.H_PUTSTATIC) {
825       constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index);
826     } else {
827       constantPool.put112(
828           tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
829     }
830     return put(
831         new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
832   }
833 
834   /**
835    * Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table.
836    *
837    * @param index the constant pool index of the new Symbol.
838    * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
839    *     Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
840    *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
841    *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
842    * @param owner the internal name of a class of interface.
843    * @param name a field or method name.
844    * @param descriptor a field or method descriptor.
845    */
addConstantMethodHandle( final int index, final int referenceKind, final String owner, final String name, final String descriptor)846   private void addConstantMethodHandle(
847       final int index,
848       final int referenceKind,
849       final String owner,
850       final String name,
851       final String descriptor) {
852     final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
853     int hashCode = hash(tag, owner, name, descriptor, referenceKind);
854     add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode));
855   }
856 
857   /**
858    * Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the
859    * constant pool already contains a similar item.
860    *
861    * @param methodDescriptor a method descriptor.
862    * @return a new or already existing Symbol with the given value.
863    */
addConstantMethodType(final String methodDescriptor)864   Symbol addConstantMethodType(final String methodDescriptor) {
865     return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor);
866   }
867 
868   /**
869    * Adds a CONSTANT_Dynamic_info to the constant pool of this symbol table. Also adds the related
870    * bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the constant
871    * pool already contains a similar item.
872    *
873    * @param name a method name.
874    * @param descriptor a field descriptor.
875    * @param bootstrapMethodHandle a bootstrap method handle.
876    * @param bootstrapMethodArguments the bootstrap method arguments.
877    * @return a new or already existing Symbol with the given value.
878    */
addConstantDynamic( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)879   Symbol addConstantDynamic(
880       final String name,
881       final String descriptor,
882       final Handle bootstrapMethodHandle,
883       final Object... bootstrapMethodArguments) {
884     Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
885     return addConstantDynamicOrInvokeDynamicReference(
886         Symbol.CONSTANT_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
887   }
888 
889   /**
890    * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the
891    * related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the
892    * constant pool already contains a similar item.
893    *
894    * @param name a method name.
895    * @param descriptor a method descriptor.
896    * @param bootstrapMethodHandle a bootstrap method handle.
897    * @param bootstrapMethodArguments the bootstrap method arguments.
898    * @return a new or already existing Symbol with the given value.
899    */
addConstantInvokeDynamic( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)900   Symbol addConstantInvokeDynamic(
901       final String name,
902       final String descriptor,
903       final Handle bootstrapMethodHandle,
904       final Object... bootstrapMethodArguments) {
905     Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
906     return addConstantDynamicOrInvokeDynamicReference(
907         Symbol.CONSTANT_INVOKE_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
908   }
909 
910   /**
911    * Adds a CONSTANT_Dynamic or a CONSTANT_InvokeDynamic_info to the constant pool of this symbol
912    * table. Does nothing if the constant pool already contains a similar item.
913    *
914    * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
915    *     Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
916    * @param name a method name.
917    * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for
918    *     CONSTANT_INVOKE_DYNAMIC_TAG.
919    * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
920    * @return a new or already existing Symbol with the given value.
921    */
addConstantDynamicOrInvokeDynamicReference( final int tag, final String name, final String descriptor, final int bootstrapMethodIndex)922   private Symbol addConstantDynamicOrInvokeDynamicReference(
923       final int tag, final String name, final String descriptor, final int bootstrapMethodIndex) {
924     int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
925     Entry entry = get(hashCode);
926     while (entry != null) {
927       if (entry.tag == tag
928           && entry.hashCode == hashCode
929           && entry.data == bootstrapMethodIndex
930           && entry.name.equals(name)
931           && entry.value.equals(descriptor)) {
932         return entry;
933       }
934       entry = entry.next;
935     }
936     constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor));
937     return put(
938         new Entry(
939             constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
940   }
941 
942   /**
943    * Adds a new CONSTANT_Dynamic_info or CONSTANT_InvokeDynamic_info to the constant pool of this
944    * symbol table.
945    *
946    * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
947    *     Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
948    * @param index the constant pool index of the new Symbol.
949    * @param name a method name.
950    * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for
951    *     CONSTANT_INVOKE_DYNAMIC_TAG.
952    * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
953    */
addConstantDynamicOrInvokeDynamicReference( final int tag, final int index, final String name, final String descriptor, final int bootstrapMethodIndex)954   private void addConstantDynamicOrInvokeDynamicReference(
955       final int tag,
956       final int index,
957       final String name,
958       final String descriptor,
959       final int bootstrapMethodIndex) {
960     int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
961     add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
962   }
963 
964   /**
965    * Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the
966    * constant pool already contains a similar item.
967    *
968    * @param moduleName a fully qualified name (using dots) of a module.
969    * @return a new or already existing Symbol with the given value.
970    */
addConstantModule(final String moduleName)971   Symbol addConstantModule(final String moduleName) {
972     return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName);
973   }
974 
975   /**
976    * Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the
977    * constant pool already contains a similar item.
978    *
979    * @param packageName the internal name of a package.
980    * @return a new or already existing Symbol with the given value.
981    */
addConstantPackage(final String packageName)982   Symbol addConstantPackage(final String packageName) {
983     return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName);
984   }
985 
986   /**
987    * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
988    * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does
989    * nothing if the constant pool already contains a similar item.
990    *
991    * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
992    *     Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
993    *     Symbol#CONSTANT_PACKAGE_TAG}.
994    * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
995    *     package name, depending on tag.
996    * @return a new or already existing Symbol with the given value.
997    */
addConstantUtf8Reference(final int tag, final String value)998   private Symbol addConstantUtf8Reference(final int tag, final String value) {
999     int hashCode = hash(tag, value);
1000     Entry entry = get(hashCode);
1001     while (entry != null) {
1002       if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) {
1003         return entry;
1004       }
1005       entry = entry.next;
1006     }
1007     constantPool.put12(tag, addConstantUtf8(value));
1008     return put(new Entry(constantPoolCount++, tag, value, hashCode));
1009   }
1010 
1011   /**
1012    * Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
1013    * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table.
1014    *
1015    * @param index the constant pool index of the new Symbol.
1016    * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
1017    *     Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
1018    *     Symbol#CONSTANT_PACKAGE_TAG}.
1019    * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
1020    *     package name, depending on tag.
1021    */
addConstantUtf8Reference(final int index, final int tag, final String value)1022   private void addConstantUtf8Reference(final int index, final int tag, final String value) {
1023     add(new Entry(index, tag, value, hash(tag, value)));
1024   }
1025 
1026   // -----------------------------------------------------------------------------------------------
1027   // Bootstrap method entries management.
1028   // -----------------------------------------------------------------------------------------------
1029 
1030   /**
1031    * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
1032    * the BootstrapMethods already contains a similar bootstrap method.
1033    *
1034    * @param bootstrapMethodHandle a bootstrap method handle.
1035    * @param bootstrapMethodArguments the bootstrap method arguments.
1036    * @return a new or already existing Symbol with the given value.
1037    */
addBootstrapMethod( final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)1038   Symbol addBootstrapMethod(
1039       final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) {
1040     ByteVector bootstrapMethodsAttribute = bootstrapMethods;
1041     if (bootstrapMethodsAttribute == null) {
1042       bootstrapMethodsAttribute = bootstrapMethods = new ByteVector();
1043     }
1044 
1045     // The bootstrap method arguments can be Constant_Dynamic values, which reference other
1046     // bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
1047     // and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
1048     // while adding the given bootstrap method to it, in the rest of this method.
1049     int numBootstrapArguments = bootstrapMethodArguments.length;
1050     int[] bootstrapMethodArgumentIndexes = new int[numBootstrapArguments];
1051     for (int i = 0; i < numBootstrapArguments; i++) {
1052       bootstrapMethodArgumentIndexes[i] = addConstant(bootstrapMethodArguments[i]).index;
1053     }
1054 
1055     // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
1056     // compare it with existing ones, and will be reverted below if there is already a similar
1057     // bootstrap method.
1058     int bootstrapMethodOffset = bootstrapMethodsAttribute.length;
1059     bootstrapMethodsAttribute.putShort(
1060         addConstantMethodHandle(
1061                 bootstrapMethodHandle.getTag(),
1062                 bootstrapMethodHandle.getOwner(),
1063                 bootstrapMethodHandle.getName(),
1064                 bootstrapMethodHandle.getDesc(),
1065                 bootstrapMethodHandle.isInterface())
1066             .index);
1067 
1068     bootstrapMethodsAttribute.putShort(numBootstrapArguments);
1069     for (int i = 0; i < numBootstrapArguments; i++) {
1070       bootstrapMethodsAttribute.putShort(bootstrapMethodArgumentIndexes[i]);
1071     }
1072 
1073     // Compute the length and the hash code of the bootstrap method.
1074     int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset;
1075     int hashCode = bootstrapMethodHandle.hashCode();
1076     for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
1077       hashCode ^= bootstrapMethodArgument.hashCode();
1078     }
1079     hashCode &= 0x7FFFFFFF;
1080 
1081     // Add the bootstrap method to the symbol table or revert the above changes.
1082     return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode);
1083   }
1084 
1085   /**
1086    * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
1087    * the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the
1088    * content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method).
1089    *
1090    * @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes.
1091    * @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes.
1092    * @param hashCode the hash code of this bootstrap method.
1093    * @return a new or already existing Symbol with the given value.
1094    */
addBootstrapMethod(final int offset, final int length, final int hashCode)1095   private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) {
1096     final byte[] bootstrapMethodsData = bootstrapMethods.data;
1097     Entry entry = get(hashCode);
1098     while (entry != null) {
1099       if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) {
1100         int otherOffset = (int) entry.data;
1101         boolean isSameBootstrapMethod = true;
1102         for (int i = 0; i < length; ++i) {
1103           if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) {
1104             isSameBootstrapMethod = false;
1105             break;
1106           }
1107         }
1108         if (isSameBootstrapMethod) {
1109           bootstrapMethods.length = offset; // Revert to old position.
1110           return entry;
1111         }
1112       }
1113       entry = entry.next;
1114     }
1115     return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode));
1116   }
1117 
1118   // -----------------------------------------------------------------------------------------------
1119   // Type table entries management.
1120   // -----------------------------------------------------------------------------------------------
1121 
1122   /**
1123    * Returns the type table element whose index is given.
1124    *
1125    * @param typeIndex a type table index.
1126    * @return the type table element whose index is given.
1127    */
getType(final int typeIndex)1128   Symbol getType(final int typeIndex) {
1129     return typeTable[typeIndex];
1130   }
1131 
1132   /**
1133    * Adds a type in the type table of this symbol table. Does nothing if the type table already
1134    * contains a similar type.
1135    *
1136    * @param value an internal class name.
1137    * @return the index of a new or already existing type Symbol with the given value.
1138    */
addType(final String value)1139   int addType(final String value) {
1140     int hashCode = hash(Symbol.TYPE_TAG, value);
1141     Entry entry = get(hashCode);
1142     while (entry != null) {
1143       if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) {
1144         return entry.index;
1145       }
1146       entry = entry.next;
1147     }
1148     return addTypeInternal(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode));
1149   }
1150 
1151   /**
1152    * Adds an {@link Frame#ITEM_UNINITIALIZED} type in the type table of this symbol table. Does
1153    * nothing if the type table already contains a similar type.
1154    *
1155    * @param value an internal class name.
1156    * @param bytecodeOffset the bytecode offset of the NEW instruction that created this {@link
1157    *     Frame#ITEM_UNINITIALIZED} type value.
1158    * @return the index of a new or already existing type Symbol with the given value.
1159    */
addUninitializedType(final String value, final int bytecodeOffset)1160   int addUninitializedType(final String value, final int bytecodeOffset) {
1161     int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset);
1162     Entry entry = get(hashCode);
1163     while (entry != null) {
1164       if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG
1165           && entry.hashCode == hashCode
1166           && entry.data == bytecodeOffset
1167           && entry.value.equals(value)) {
1168         return entry.index;
1169       }
1170       entry = entry.next;
1171     }
1172     return addTypeInternal(
1173         new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode));
1174   }
1175 
1176   /**
1177    * Adds a merged type in the type table of this symbol table. Does nothing if the type table
1178    * already contains a similar type.
1179    *
1180    * @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type
1181    *     table.
1182    * @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type
1183    *     table.
1184    * @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol,
1185    *     corresponding to the common super class of the given types.
1186    */
addMergedType(final int typeTableIndex1, final int typeTableIndex2)1187   int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
1188     long data =
1189         typeTableIndex1 < typeTableIndex2
1190             ? typeTableIndex1 | (((long) typeTableIndex2) << 32)
1191             : typeTableIndex2 | (((long) typeTableIndex1) << 32);
1192     int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2);
1193     Entry entry = get(hashCode);
1194     while (entry != null) {
1195       if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) {
1196         return entry.info;
1197       }
1198       entry = entry.next;
1199     }
1200     String type1 = typeTable[typeTableIndex1].value;
1201     String type2 = typeTable[typeTableIndex2].value;
1202     int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2));
1203     put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex;
1204     return commonSuperTypeIndex;
1205   }
1206 
1207   /**
1208    * Adds the given type Symbol to {@link #typeTable}.
1209    *
1210    * @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol.
1211    *     The index of this Symbol must be equal to the current value of {@link #typeCount}.
1212    * @return the index in {@link #typeTable} where the given type was added, which is also equal to
1213    *     entry's index by hypothesis.
1214    */
1215   private int addTypeInternal(final Entry entry) {
1216     if (typeTable == null) {
1217       typeTable = new Entry[16];
1218     }
1219     if (typeCount == typeTable.length) {
1220       Entry[] newTypeTable = new Entry[2 * typeTable.length];
1221       System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length);
1222       typeTable = newTypeTable;
1223     }
1224     typeTable[typeCount++] = entry;
1225     return put(entry).index;
1226   }
1227 
1228   // -----------------------------------------------------------------------------------------------
1229   // Static helper methods to compute hash codes.
1230   // -----------------------------------------------------------------------------------------------
1231 
1232   private static int hash(final int tag, final int value) {
1233     return 0x7FFFFFFF & (tag + value);
1234   }
1235 
1236   private static int hash(final int tag, final long value) {
1237     return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32));
1238   }
1239 
1240   private static int hash(final int tag, final String value) {
1241     return 0x7FFFFFFF & (tag + value.hashCode());
1242   }
1243 
1244   private static int hash(final int tag, final String value1, final int value2) {
1245     return 0x7FFFFFFF & (tag + value1.hashCode() + value2);
1246   }
1247 
1248   private static int hash(final int tag, final String value1, final String value2) {
1249     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode());
1250   }
1251 
1252   private static int hash(
1253       final int tag, final String value1, final String value2, final int value3) {
1254     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1));
1255   }
1256 
1257   private static int hash(
1258       final int tag, final String value1, final String value2, final String value3) {
1259     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode());
1260   }
1261 
1262   private static int hash(
1263       final int tag,
1264       final String value1,
1265       final String value2,
1266       final String value3,
1267       final int value4) {
1268     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4);
1269   }
1270 
1271   /**
1272    * An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields
1273    * which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid
1274    * duplicate symbols). See {@link #entries}.
1275    *
1276    * @author Eric Bruneton
1277    */
1278   private static class Entry extends Symbol {
1279 
1280     /** The hash code of this entry. */
1281     final int hashCode;
1282 
1283     /**
1284      * Another entry (and so on recursively) having the same hash code (modulo the size of {@link
1285      * #entries}) as this one.
1286      */
1287     Entry next;
1288 
1289     Entry(
1290         final int index,
1291         final int tag,
1292         final String owner,
1293         final String name,
1294         final String value,
1295         final long data,
1296         final int hashCode) {
1297       super(index, tag, owner, name, value, data);
1298       this.hashCode = hashCode;
1299     }
1300 
1301     Entry(final int index, final int tag, final String value, final int hashCode) {
1302       super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0);
1303       this.hashCode = hashCode;
1304     }
1305 
1306     Entry(final int index, final int tag, final String value, final long data, final int hashCode) {
1307       super(index, tag, /* owner = */ null, /* name = */ null, value, data);
1308       this.hashCode = hashCode;
1309     }
1310 
1311     Entry(
1312         final int index, final int tag, final String name, final String value, final int hashCode) {
1313       super(index, tag, /* owner = */ null, name, value, /* data = */ 0);
1314       this.hashCode = hashCode;
1315     }
1316 
1317     Entry(final int index, final int tag, final long data, final int hashCode) {
1318       super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data);
1319       this.hashCode = hashCode;
1320     }
1321   }
1322 }
1323