• 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}, {@link Symbol#UNINITIALIZED_TYPE_TAG},{@link
112    * Symbol#FORWARD_UNINITIALIZED_TYPE_TAG} and {@link Symbol#MERGED_TYPE_TAG} entries. The type
113    * symbol at index {@code i} has its {@link Symbol#index} equal to {@code i} (and vice versa).
114    */
115   private Entry[] typeTable;
116 
117   /**
118    * The actual number of {@link LabelEntry} in {@link #labelTable}. These elements are stored from
119    * index 0 to labelCount (excluded). The other array entries are empty. These label entries are
120    * also stored in the {@link #labelEntries} hash set.
121    */
122   private int labelCount;
123 
124   /**
125    * The labels corresponding to the "forward uninitialized" types in the ASM specific {@link
126    * typeTable} (see {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}). The label entry at index {@code
127    * i} has its {@link LabelEntry#index} equal to {@code i} (and vice versa).
128    */
129   private LabelEntry[] labelTable;
130 
131   /**
132    * A hash set of all the {@link LabelEntry} elements in the {@link #labelTable}. Each {@link
133    * LabelEntry} instance is stored at the array index given by its hash code modulo the array size.
134    * If several entries must be stored at the same array index, they are linked together via their
135    * {@link LabelEntry#next} field. The {@link #getOrAddLabelEntry(Label)} method ensures that this
136    * table does not contain duplicated entries.
137    */
138   private LabelEntry[] labelEntries;
139 
140   /**
141    * Constructs a new, empty SymbolTable for the given ClassWriter.
142    *
143    * @param classWriter a ClassWriter.
144    */
SymbolTable(final ClassWriter classWriter)145   SymbolTable(final ClassWriter classWriter) {
146     this.classWriter = classWriter;
147     this.sourceClassReader = null;
148     this.entries = new Entry[256];
149     this.constantPoolCount = 1;
150     this.constantPool = new ByteVector();
151   }
152 
153   /**
154    * Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and
155    * bootstrap methods of the given ClassReader.
156    *
157    * @param classWriter a ClassWriter.
158    * @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to
159    *     initialize the SymbolTable.
160    */
SymbolTable(final ClassWriter classWriter, final ClassReader classReader)161   SymbolTable(final ClassWriter classWriter, final ClassReader classReader) {
162     this.classWriter = classWriter;
163     this.sourceClassReader = classReader;
164 
165     // Copy the constant pool binary content.
166     byte[] inputBytes = classReader.classFileBuffer;
167     int constantPoolOffset = classReader.getItem(1) - 1;
168     int constantPoolLength = classReader.header - constantPoolOffset;
169     constantPoolCount = classReader.getItemCount();
170     constantPool = new ByteVector(constantPoolLength);
171     constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength);
172 
173     // Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to
174     // avoid too many hash set collisions (entries is not dynamically resized by the addConstant*
175     // method calls below), and to account for bootstrap method entries.
176     entries = new Entry[constantPoolCount * 2];
177     char[] charBuffer = new char[classReader.getMaxStringLength()];
178     boolean hasBootstrapMethods = false;
179     int itemIndex = 1;
180     while (itemIndex < constantPoolCount) {
181       int itemOffset = classReader.getItem(itemIndex);
182       int itemTag = inputBytes[itemOffset - 1];
183       int nameAndTypeItemOffset;
184       switch (itemTag) {
185         case Symbol.CONSTANT_FIELDREF_TAG:
186         case Symbol.CONSTANT_METHODREF_TAG:
187         case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
188           nameAndTypeItemOffset =
189               classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
190           addConstantMemberReference(
191               itemIndex,
192               itemTag,
193               classReader.readClass(itemOffset, charBuffer),
194               classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
195               classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
196           break;
197         case Symbol.CONSTANT_INTEGER_TAG:
198         case Symbol.CONSTANT_FLOAT_TAG:
199           addConstantIntegerOrFloat(itemIndex, itemTag, classReader.readInt(itemOffset));
200           break;
201         case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
202           addConstantNameAndType(
203               itemIndex,
204               classReader.readUTF8(itemOffset, charBuffer),
205               classReader.readUTF8(itemOffset + 2, charBuffer));
206           break;
207         case Symbol.CONSTANT_LONG_TAG:
208         case Symbol.CONSTANT_DOUBLE_TAG:
209           addConstantLongOrDouble(itemIndex, itemTag, classReader.readLong(itemOffset));
210           break;
211         case Symbol.CONSTANT_UTF8_TAG:
212           addConstantUtf8(itemIndex, classReader.readUtf(itemIndex, charBuffer));
213           break;
214         case Symbol.CONSTANT_METHOD_HANDLE_TAG:
215           int memberRefItemOffset =
216               classReader.getItem(classReader.readUnsignedShort(itemOffset + 1));
217           nameAndTypeItemOffset =
218               classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2));
219           addConstantMethodHandle(
220               itemIndex,
221               classReader.readByte(itemOffset),
222               classReader.readClass(memberRefItemOffset, charBuffer),
223               classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
224               classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer));
225           break;
226         case Symbol.CONSTANT_DYNAMIC_TAG:
227         case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
228           hasBootstrapMethods = true;
229           nameAndTypeItemOffset =
230               classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
231           addConstantDynamicOrInvokeDynamicReference(
232               itemTag,
233               itemIndex,
234               classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
235               classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer),
236               classReader.readUnsignedShort(itemOffset));
237           break;
238         case Symbol.CONSTANT_STRING_TAG:
239         case Symbol.CONSTANT_CLASS_TAG:
240         case Symbol.CONSTANT_METHOD_TYPE_TAG:
241         case Symbol.CONSTANT_MODULE_TAG:
242         case Symbol.CONSTANT_PACKAGE_TAG:
243           addConstantUtf8Reference(
244               itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer));
245           break;
246         default:
247           throw new IllegalArgumentException();
248       }
249       itemIndex +=
250           (itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1;
251     }
252 
253     // Copy the BootstrapMethods, if any.
254     if (hasBootstrapMethods) {
255       copyBootstrapMethods(classReader, charBuffer);
256     }
257   }
258 
259   /**
260    * Read the BootstrapMethods 'bootstrap_methods' array binary content and add them as entries of
261    * the SymbolTable.
262    *
263    * @param classReader the ClassReader whose bootstrap methods must be copied to initialize the
264    *     SymbolTable.
265    * @param charBuffer a buffer used to read strings in the constant pool.
266    */
copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer)267   private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) {
268     // Find attributOffset of the 'bootstrap_methods' array.
269     byte[] inputBytes = classReader.classFileBuffer;
270     int currentAttributeOffset = classReader.getFirstAttributeOffset();
271     for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
272       String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
273       if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
274         bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6);
275         break;
276       }
277       currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2);
278     }
279     if (bootstrapMethodCount > 0) {
280       // Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array.
281       int bootstrapMethodsOffset = currentAttributeOffset + 8;
282       int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2;
283       bootstrapMethods = new ByteVector(bootstrapMethodsLength);
284       bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength);
285 
286       // Add each bootstrap method in the symbol table entries.
287       int currentOffset = bootstrapMethodsOffset;
288       for (int i = 0; i < bootstrapMethodCount; i++) {
289         int offset = currentOffset - bootstrapMethodsOffset;
290         int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset);
291         currentOffset += 2;
292         int numBootstrapArguments = classReader.readUnsignedShort(currentOffset);
293         currentOffset += 2;
294         int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode();
295         while (numBootstrapArguments-- > 0) {
296           int bootstrapArgument = classReader.readUnsignedShort(currentOffset);
297           currentOffset += 2;
298           hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode();
299         }
300         add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF));
301       }
302     }
303   }
304 
305   /**
306    * Returns the ClassReader from which this SymbolTable was constructed.
307    *
308    * @return the ClassReader from which this SymbolTable was constructed, or {@literal null} if it
309    *     was constructed from scratch.
310    */
getSource()311   ClassReader getSource() {
312     return sourceClassReader;
313   }
314 
315   /**
316    * Returns the major version of the class to which this symbol table belongs.
317    *
318    * @return the major version of the class to which this symbol table belongs.
319    */
getMajorVersion()320   int getMajorVersion() {
321     return majorVersion;
322   }
323 
324   /**
325    * Returns the internal name of the class to which this symbol table belongs.
326    *
327    * @return the internal name of the class to which this symbol table belongs.
328    */
getClassName()329   String getClassName() {
330     return className;
331   }
332 
333   /**
334    * Sets the major version and the name of the class to which this symbol table belongs. Also adds
335    * the class name to the constant pool.
336    *
337    * @param majorVersion a major ClassFile version number.
338    * @param className an internal class name.
339    * @return the constant pool index of a new or already existing Symbol with the given class name.
340    */
setMajorVersionAndClassName(final int majorVersion, final String className)341   int setMajorVersionAndClassName(final int majorVersion, final String className) {
342     this.majorVersion = majorVersion;
343     this.className = className;
344     return addConstantClass(className).index;
345   }
346 
347   /**
348    * Returns the number of items in this symbol table's constant_pool array (plus 1).
349    *
350    * @return the number of items in this symbol table's constant_pool array (plus 1).
351    */
getConstantPoolCount()352   int getConstantPoolCount() {
353     return constantPoolCount;
354   }
355 
356   /**
357    * Returns the length in bytes of this symbol table's constant_pool array.
358    *
359    * @return the length in bytes of this symbol table's constant_pool array.
360    */
getConstantPoolLength()361   int getConstantPoolLength() {
362     return constantPool.length;
363   }
364 
365   /**
366    * Puts this symbol table's constant_pool array in the given ByteVector, preceded by the
367    * constant_pool_count value.
368    *
369    * @param output where the JVMS ClassFile's constant_pool array must be put.
370    */
putConstantPool(final ByteVector output)371   void putConstantPool(final ByteVector output) {
372     output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length);
373   }
374 
375   /**
376    * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the
377    * attribute name in the constant pool.
378    *
379    * @return the size in bytes of this symbol table's BootstrapMethods attribute.
380    */
computeBootstrapMethodsSize()381   int computeBootstrapMethodsSize() {
382     if (bootstrapMethods != null) {
383       addConstantUtf8(Constants.BOOTSTRAP_METHODS);
384       return 8 + bootstrapMethods.length;
385     } else {
386       return 0;
387     }
388   }
389 
390   /**
391    * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the
392    * 6 attribute header bytes and the num_bootstrap_methods value.
393    *
394    * @param output where the JVMS BootstrapMethods attribute must be put.
395    */
putBootstrapMethods(final ByteVector output)396   void putBootstrapMethods(final ByteVector output) {
397     if (bootstrapMethods != null) {
398       output
399           .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS))
400           .putInt(bootstrapMethods.length + 2)
401           .putShort(bootstrapMethodCount)
402           .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
403     }
404   }
405 
406   // -----------------------------------------------------------------------------------------------
407   // Generic symbol table entries management.
408   // -----------------------------------------------------------------------------------------------
409 
410   /**
411    * Returns the list of entries which can potentially have the given hash code.
412    *
413    * @param hashCode a {@link Entry#hashCode} value.
414    * @return the list of entries which can potentially have the given hash code. The list is stored
415    *     via the {@link Entry#next} field.
416    */
get(final int hashCode)417   private Entry get(final int hashCode) {
418     return entries[hashCode % entries.length];
419   }
420 
421   /**
422    * Puts the given entry in the {@link #entries} hash set. This method does <i>not</i> check
423    * whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized
424    * if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link
425    * #entries} array index) as much as possible, with reasonable memory usage.
426    *
427    * @param entry an Entry (which must not already be contained in {@link #entries}).
428    * @return the given entry
429    */
put(final Entry entry)430   private Entry put(final Entry entry) {
431     if (entryCount > (entries.length * 3) / 4) {
432       int currentCapacity = entries.length;
433       int newCapacity = currentCapacity * 2 + 1;
434       Entry[] newEntries = new Entry[newCapacity];
435       for (int i = currentCapacity - 1; i >= 0; --i) {
436         Entry currentEntry = entries[i];
437         while (currentEntry != null) {
438           int newCurrentEntryIndex = currentEntry.hashCode % newCapacity;
439           Entry nextEntry = currentEntry.next;
440           currentEntry.next = newEntries[newCurrentEntryIndex];
441           newEntries[newCurrentEntryIndex] = currentEntry;
442           currentEntry = nextEntry;
443         }
444       }
445       entries = newEntries;
446     }
447     entryCount++;
448     int index = entry.hashCode % entries.length;
449     entry.next = entries[index];
450     return entries[index] = entry;
451   }
452 
453   /**
454    * Adds the given entry in the {@link #entries} hash set. This method does <i>not</i> check
455    * whether {@link #entries} already contains a similar entry or not, and does <i>not</i> resize
456    * {@link #entries} if necessary.
457    *
458    * @param entry an Entry (which must not already be contained in {@link #entries}).
459    */
add(final Entry entry)460   private void add(final Entry entry) {
461     entryCount++;
462     int index = entry.hashCode % entries.length;
463     entry.next = entries[index];
464     entries[index] = entry;
465   }
466 
467   // -----------------------------------------------------------------------------------------------
468   // Constant pool entries management.
469   // -----------------------------------------------------------------------------------------------
470 
471   /**
472    * Adds a number or string constant to the constant pool of this symbol table. Does nothing if the
473    * constant pool already contains a similar item.
474    *
475    * @param value the value of the constant to be added to the constant pool. This parameter must be
476    *     an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link
477    *     Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}.
478    * @return a new or already existing Symbol with the given value.
479    */
addConstant(final Object value)480   Symbol addConstant(final Object value) {
481     if (value instanceof Integer) {
482       return addConstantInteger(((Integer) value).intValue());
483     } else if (value instanceof Byte) {
484       return addConstantInteger(((Byte) value).intValue());
485     } else if (value instanceof Character) {
486       return addConstantInteger(((Character) value).charValue());
487     } else if (value instanceof Short) {
488       return addConstantInteger(((Short) value).intValue());
489     } else if (value instanceof Boolean) {
490       return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0);
491     } else if (value instanceof Float) {
492       return addConstantFloat(((Float) value).floatValue());
493     } else if (value instanceof Long) {
494       return addConstantLong(((Long) value).longValue());
495     } else if (value instanceof Double) {
496       return addConstantDouble(((Double) value).doubleValue());
497     } else if (value instanceof String) {
498       return addConstantString((String) value);
499     } else if (value instanceof Type) {
500       Type type = (Type) value;
501       int typeSort = type.getSort();
502       if (typeSort == Type.OBJECT) {
503         return addConstantClass(type.getInternalName());
504       } else if (typeSort == Type.METHOD) {
505         return addConstantMethodType(type.getDescriptor());
506       } else { // type is a primitive or array type.
507         return addConstantClass(type.getDescriptor());
508       }
509     } else if (value instanceof Handle) {
510       Handle handle = (Handle) value;
511       return addConstantMethodHandle(
512           handle.getTag(),
513           handle.getOwner(),
514           handle.getName(),
515           handle.getDesc(),
516           handle.isInterface());
517     } else if (value instanceof ConstantDynamic) {
518       ConstantDynamic constantDynamic = (ConstantDynamic) value;
519       return addConstantDynamic(
520           constantDynamic.getName(),
521           constantDynamic.getDescriptor(),
522           constantDynamic.getBootstrapMethod(),
523           constantDynamic.getBootstrapMethodArgumentsUnsafe());
524     } else {
525       throw new IllegalArgumentException("value " + value);
526     }
527   }
528 
529   /**
530    * Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the
531    * constant pool already contains a similar item.
532    *
533    * @param value the internal name of a class.
534    * @return a new or already existing Symbol with the given value.
535    */
addConstantClass(final String value)536   Symbol addConstantClass(final String value) {
537     return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value);
538   }
539 
540   /**
541    * Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the
542    * constant pool already contains a similar item.
543    *
544    * @param owner the internal name of a class.
545    * @param name a field name.
546    * @param descriptor a field descriptor.
547    * @return a new or already existing Symbol with the given value.
548    */
addConstantFieldref(final String owner, final String name, final String descriptor)549   Symbol addConstantFieldref(final String owner, final String name, final String descriptor) {
550     return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor);
551   }
552 
553   /**
554    * Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this
555    * symbol table. Does nothing if the constant pool already contains a similar item.
556    *
557    * @param owner the internal name of a class.
558    * @param name a method name.
559    * @param descriptor a method descriptor.
560    * @param isInterface whether owner is an interface or not.
561    * @return a new or already existing Symbol with the given value.
562    */
addConstantMethodref( final String owner, final String name, final String descriptor, final boolean isInterface)563   Symbol addConstantMethodref(
564       final String owner, final String name, final String descriptor, final boolean isInterface) {
565     int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG;
566     return addConstantMemberReference(tag, owner, name, descriptor);
567   }
568 
569   /**
570    * Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to
571    * the constant pool of this symbol table. Does nothing if the constant pool already contains a
572    * similar item.
573    *
574    * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
575    *     or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
576    * @param owner the internal name of a class.
577    * @param name a field or method name.
578    * @param descriptor a field or method descriptor.
579    * @return a new or already existing Symbol with the given value.
580    */
addConstantMemberReference( final int tag, final String owner, final String name, final String descriptor)581   private Entry addConstantMemberReference(
582       final int tag, final String owner, final String name, final String descriptor) {
583     int hashCode = hash(tag, owner, name, descriptor);
584     Entry entry = get(hashCode);
585     while (entry != null) {
586       if (entry.tag == tag
587           && entry.hashCode == hashCode
588           && entry.owner.equals(owner)
589           && entry.name.equals(name)
590           && entry.value.equals(descriptor)) {
591         return entry;
592       }
593       entry = entry.next;
594     }
595     constantPool.put122(
596         tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor));
597     return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode));
598   }
599 
600   /**
601    * Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info
602    * to the constant pool of this symbol table.
603    *
604    * @param index the constant pool index of the new Symbol.
605    * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG}
606    *     or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}.
607    * @param owner the internal name of a class.
608    * @param name a field or method name.
609    * @param descriptor a field or method descriptor.
610    */
addConstantMemberReference( final int index, final int tag, final String owner, final String name, final String descriptor)611   private void addConstantMemberReference(
612       final int index,
613       final int tag,
614       final String owner,
615       final String name,
616       final String descriptor) {
617     add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor)));
618   }
619 
620   /**
621    * Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the
622    * constant pool already contains a similar item.
623    *
624    * @param value a string.
625    * @return a new or already existing Symbol with the given value.
626    */
addConstantString(final String value)627   Symbol addConstantString(final String value) {
628     return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value);
629   }
630 
631   /**
632    * Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the
633    * constant pool already contains a similar item.
634    *
635    * @param value an int.
636    * @return a new or already existing Symbol with the given value.
637    */
addConstantInteger(final int value)638   Symbol addConstantInteger(final int value) {
639     return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, value);
640   }
641 
642   /**
643    * Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the
644    * constant pool already contains a similar item.
645    *
646    * @param value a float.
647    * @return a new or already existing Symbol with the given value.
648    */
addConstantFloat(final float value)649   Symbol addConstantFloat(final float value) {
650     return addConstantIntegerOrFloat(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value));
651   }
652 
653   /**
654    * Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table.
655    * Does nothing if the constant pool already contains a similar item.
656    *
657    * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
658    * @param value an int or float.
659    * @return a constant pool constant with the given tag and primitive values.
660    */
addConstantIntegerOrFloat(final int tag, final int value)661   private Symbol addConstantIntegerOrFloat(final int tag, final int value) {
662     int hashCode = hash(tag, value);
663     Entry entry = get(hashCode);
664     while (entry != null) {
665       if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
666         return entry;
667       }
668       entry = entry.next;
669     }
670     constantPool.putByte(tag).putInt(value);
671     return put(new Entry(constantPoolCount++, tag, value, hashCode));
672   }
673 
674   /**
675    * Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol
676    * table.
677    *
678    * @param index the constant pool index of the new Symbol.
679    * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}.
680    * @param value an int or float.
681    */
addConstantIntegerOrFloat(final int index, final int tag, final int value)682   private void addConstantIntegerOrFloat(final int index, final int tag, final int value) {
683     add(new Entry(index, tag, value, hash(tag, value)));
684   }
685 
686   /**
687    * Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the
688    * constant pool already contains a similar item.
689    *
690    * @param value a long.
691    * @return a new or already existing Symbol with the given value.
692    */
addConstantLong(final long value)693   Symbol addConstantLong(final long value) {
694     return addConstantLongOrDouble(Symbol.CONSTANT_LONG_TAG, value);
695   }
696 
697   /**
698    * Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the
699    * constant pool already contains a similar item.
700    *
701    * @param value a double.
702    * @return a new or already existing Symbol with the given value.
703    */
addConstantDouble(final double value)704   Symbol addConstantDouble(final double value) {
705     return addConstantLongOrDouble(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value));
706   }
707 
708   /**
709    * Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table.
710    * Does nothing if the constant pool already contains a similar item.
711    *
712    * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
713    * @param value a long or double.
714    * @return a constant pool constant with the given tag and primitive values.
715    */
addConstantLongOrDouble(final int tag, final long value)716   private Symbol addConstantLongOrDouble(final int tag, final long value) {
717     int hashCode = hash(tag, value);
718     Entry entry = get(hashCode);
719     while (entry != null) {
720       if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) {
721         return entry;
722       }
723       entry = entry.next;
724     }
725     int index = constantPoolCount;
726     constantPool.putByte(tag).putLong(value);
727     constantPoolCount += 2;
728     return put(new Entry(index, tag, value, hashCode));
729   }
730 
731   /**
732    * Adds a new CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol
733    * table.
734    *
735    * @param index the constant pool index of the new Symbol.
736    * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}.
737    * @param value a long or double.
738    */
addConstantLongOrDouble(final int index, final int tag, final long value)739   private void addConstantLongOrDouble(final int index, final int tag, final long value) {
740     add(new Entry(index, tag, value, hash(tag, value)));
741   }
742 
743   /**
744    * Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the
745    * constant pool already contains a similar item.
746    *
747    * @param name a field or method name.
748    * @param descriptor a field or method descriptor.
749    * @return a new or already existing Symbol with the given value.
750    */
addConstantNameAndType(final String name, final String descriptor)751   int addConstantNameAndType(final String name, final String descriptor) {
752     final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
753     int hashCode = hash(tag, name, descriptor);
754     Entry entry = get(hashCode);
755     while (entry != null) {
756       if (entry.tag == tag
757           && entry.hashCode == hashCode
758           && entry.name.equals(name)
759           && entry.value.equals(descriptor)) {
760         return entry.index;
761       }
762       entry = entry.next;
763     }
764     constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor));
765     return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index;
766   }
767 
768   /**
769    * Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table.
770    *
771    * @param index the constant pool index of the new Symbol.
772    * @param name a field or method name.
773    * @param descriptor a field or method descriptor.
774    */
addConstantNameAndType(final int index, final String name, final String descriptor)775   private void addConstantNameAndType(final int index, final String name, final String descriptor) {
776     final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG;
777     add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor)));
778   }
779 
780   /**
781    * Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the
782    * constant pool already contains a similar item.
783    *
784    * @param value a string.
785    * @return a new or already existing Symbol with the given value.
786    */
addConstantUtf8(final String value)787   int addConstantUtf8(final String value) {
788     int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value);
789     Entry entry = get(hashCode);
790     while (entry != null) {
791       if (entry.tag == Symbol.CONSTANT_UTF8_TAG
792           && entry.hashCode == hashCode
793           && entry.value.equals(value)) {
794         return entry.index;
795       }
796       entry = entry.next;
797     }
798     constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value);
799     return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index;
800   }
801 
802   /**
803    * Adds a new CONSTANT_String_info to the constant pool of this symbol table.
804    *
805    * @param index the constant pool index of the new Symbol.
806    * @param value a string.
807    */
addConstantUtf8(final int index, final String value)808   private void addConstantUtf8(final int index, final String value) {
809     add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value)));
810   }
811 
812   /**
813    * Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if
814    * the constant pool already contains a similar item.
815    *
816    * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
817    *     Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
818    *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
819    *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
820    * @param owner the internal name of a class of interface.
821    * @param name a field or method name.
822    * @param descriptor a field or method descriptor.
823    * @param isInterface whether owner is an interface or not.
824    * @return a new or already existing Symbol with the given value.
825    */
addConstantMethodHandle( final int referenceKind, final String owner, final String name, final String descriptor, final boolean isInterface)826   Symbol addConstantMethodHandle(
827       final int referenceKind,
828       final String owner,
829       final String name,
830       final String descriptor,
831       final boolean isInterface) {
832     final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
833     // Note that we don't need to include isInterface in the hash computation, because it is
834     // redundant with owner (we can't have the same owner with different isInterface values).
835     int hashCode = hash(tag, owner, name, descriptor, referenceKind);
836     Entry entry = get(hashCode);
837     while (entry != null) {
838       if (entry.tag == tag
839           && entry.hashCode == hashCode
840           && entry.data == referenceKind
841           && entry.owner.equals(owner)
842           && entry.name.equals(name)
843           && entry.value.equals(descriptor)) {
844         return entry;
845       }
846       entry = entry.next;
847     }
848     if (referenceKind <= Opcodes.H_PUTSTATIC) {
849       constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index);
850     } else {
851       constantPool.put112(
852           tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index);
853     }
854     return put(
855         new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode));
856   }
857 
858   /**
859    * Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table.
860    *
861    * @param index the constant pool index of the new Symbol.
862    * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link
863    *     Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
864    *     Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
865    *     Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
866    * @param owner the internal name of a class of interface.
867    * @param name a field or method name.
868    * @param descriptor a field or method descriptor.
869    */
addConstantMethodHandle( final int index, final int referenceKind, final String owner, final String name, final String descriptor)870   private void addConstantMethodHandle(
871       final int index,
872       final int referenceKind,
873       final String owner,
874       final String name,
875       final String descriptor) {
876     final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG;
877     int hashCode = hash(tag, owner, name, descriptor, referenceKind);
878     add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode));
879   }
880 
881   /**
882    * Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the
883    * constant pool already contains a similar item.
884    *
885    * @param methodDescriptor a method descriptor.
886    * @return a new or already existing Symbol with the given value.
887    */
addConstantMethodType(final String methodDescriptor)888   Symbol addConstantMethodType(final String methodDescriptor) {
889     return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor);
890   }
891 
892   /**
893    * Adds a CONSTANT_Dynamic_info to the constant pool of this symbol table. Also adds the related
894    * bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the constant
895    * pool already contains a similar item.
896    *
897    * @param name a method name.
898    * @param descriptor a field descriptor.
899    * @param bootstrapMethodHandle a bootstrap method handle.
900    * @param bootstrapMethodArguments the bootstrap method arguments.
901    * @return a new or already existing Symbol with the given value.
902    */
addConstantDynamic( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)903   Symbol addConstantDynamic(
904       final String name,
905       final String descriptor,
906       final Handle bootstrapMethodHandle,
907       final Object... bootstrapMethodArguments) {
908     Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
909     return addConstantDynamicOrInvokeDynamicReference(
910         Symbol.CONSTANT_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
911   }
912 
913   /**
914    * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the
915    * related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the
916    * constant pool already contains a similar item.
917    *
918    * @param name a method name.
919    * @param descriptor a method descriptor.
920    * @param bootstrapMethodHandle a bootstrap method handle.
921    * @param bootstrapMethodArguments the bootstrap method arguments.
922    * @return a new or already existing Symbol with the given value.
923    */
addConstantInvokeDynamic( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)924   Symbol addConstantInvokeDynamic(
925       final String name,
926       final String descriptor,
927       final Handle bootstrapMethodHandle,
928       final Object... bootstrapMethodArguments) {
929     Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
930     return addConstantDynamicOrInvokeDynamicReference(
931         Symbol.CONSTANT_INVOKE_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
932   }
933 
934   /**
935    * Adds a CONSTANT_Dynamic or a CONSTANT_InvokeDynamic_info to the constant pool of this symbol
936    * table. Does nothing if the constant pool already contains a similar item.
937    *
938    * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
939    *     Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
940    * @param name a method name.
941    * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for
942    *     CONSTANT_INVOKE_DYNAMIC_TAG.
943    * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
944    * @return a new or already existing Symbol with the given value.
945    */
addConstantDynamicOrInvokeDynamicReference( final int tag, final String name, final String descriptor, final int bootstrapMethodIndex)946   private Symbol addConstantDynamicOrInvokeDynamicReference(
947       final int tag, final String name, final String descriptor, final int bootstrapMethodIndex) {
948     int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
949     Entry entry = get(hashCode);
950     while (entry != null) {
951       if (entry.tag == tag
952           && entry.hashCode == hashCode
953           && entry.data == bootstrapMethodIndex
954           && entry.name.equals(name)
955           && entry.value.equals(descriptor)) {
956         return entry;
957       }
958       entry = entry.next;
959     }
960     constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor));
961     return put(
962         new Entry(
963             constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
964   }
965 
966   /**
967    * Adds a new CONSTANT_Dynamic_info or CONSTANT_InvokeDynamic_info to the constant pool of this
968    * symbol table.
969    *
970    * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link
971    *     Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
972    * @param index the constant pool index of the new Symbol.
973    * @param name a method name.
974    * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for
975    *     CONSTANT_INVOKE_DYNAMIC_TAG.
976    * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
977    */
addConstantDynamicOrInvokeDynamicReference( final int tag, final int index, final String name, final String descriptor, final int bootstrapMethodIndex)978   private void addConstantDynamicOrInvokeDynamicReference(
979       final int tag,
980       final int index,
981       final String name,
982       final String descriptor,
983       final int bootstrapMethodIndex) {
984     int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
985     add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode));
986   }
987 
988   /**
989    * Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the
990    * constant pool already contains a similar item.
991    *
992    * @param moduleName a fully qualified name (using dots) of a module.
993    * @return a new or already existing Symbol with the given value.
994    */
addConstantModule(final String moduleName)995   Symbol addConstantModule(final String moduleName) {
996     return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName);
997   }
998 
999   /**
1000    * Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the
1001    * constant pool already contains a similar item.
1002    *
1003    * @param packageName the internal name of a package.
1004    * @return a new or already existing Symbol with the given value.
1005    */
addConstantPackage(final String packageName)1006   Symbol addConstantPackage(final String packageName) {
1007     return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName);
1008   }
1009 
1010   /**
1011    * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
1012    * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does
1013    * nothing if the constant pool already contains a similar item.
1014    *
1015    * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
1016    *     Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
1017    *     Symbol#CONSTANT_PACKAGE_TAG}.
1018    * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
1019    *     package name, depending on tag.
1020    * @return a new or already existing Symbol with the given value.
1021    */
addConstantUtf8Reference(final int tag, final String value)1022   private Symbol addConstantUtf8Reference(final int tag, final String value) {
1023     int hashCode = hash(tag, value);
1024     Entry entry = get(hashCode);
1025     while (entry != null) {
1026       if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) {
1027         return entry;
1028       }
1029       entry = entry.next;
1030     }
1031     constantPool.put12(tag, addConstantUtf8(value));
1032     return put(new Entry(constantPoolCount++, tag, value, hashCode));
1033   }
1034 
1035   /**
1036    * Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info,
1037    * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table.
1038    *
1039    * @param index the constant pool index of the new Symbol.
1040    * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link
1041    *     Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link
1042    *     Symbol#CONSTANT_PACKAGE_TAG}.
1043    * @param value an internal class name, an arbitrary string, a method descriptor, a module or a
1044    *     package name, depending on tag.
1045    */
addConstantUtf8Reference(final int index, final int tag, final String value)1046   private void addConstantUtf8Reference(final int index, final int tag, final String value) {
1047     add(new Entry(index, tag, value, hash(tag, value)));
1048   }
1049 
1050   // -----------------------------------------------------------------------------------------------
1051   // Bootstrap method entries management.
1052   // -----------------------------------------------------------------------------------------------
1053 
1054   /**
1055    * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
1056    * the BootstrapMethods already contains a similar bootstrap method.
1057    *
1058    * @param bootstrapMethodHandle a bootstrap method handle.
1059    * @param bootstrapMethodArguments the bootstrap method arguments.
1060    * @return a new or already existing Symbol with the given value.
1061    */
addBootstrapMethod( final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)1062   Symbol addBootstrapMethod(
1063       final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) {
1064     ByteVector bootstrapMethodsAttribute = bootstrapMethods;
1065     if (bootstrapMethodsAttribute == null) {
1066       bootstrapMethodsAttribute = bootstrapMethods = new ByteVector();
1067     }
1068 
1069     // The bootstrap method arguments can be Constant_Dynamic values, which reference other
1070     // bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
1071     // and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
1072     // while adding the given bootstrap method to it, in the rest of this method.
1073     int numBootstrapArguments = bootstrapMethodArguments.length;
1074     int[] bootstrapMethodArgumentIndexes = new int[numBootstrapArguments];
1075     for (int i = 0; i < numBootstrapArguments; i++) {
1076       bootstrapMethodArgumentIndexes[i] = addConstant(bootstrapMethodArguments[i]).index;
1077     }
1078 
1079     // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
1080     // compare it with existing ones, and will be reverted below if there is already a similar
1081     // bootstrap method.
1082     int bootstrapMethodOffset = bootstrapMethodsAttribute.length;
1083     bootstrapMethodsAttribute.putShort(
1084         addConstantMethodHandle(
1085                 bootstrapMethodHandle.getTag(),
1086                 bootstrapMethodHandle.getOwner(),
1087                 bootstrapMethodHandle.getName(),
1088                 bootstrapMethodHandle.getDesc(),
1089                 bootstrapMethodHandle.isInterface())
1090             .index);
1091 
1092     bootstrapMethodsAttribute.putShort(numBootstrapArguments);
1093     for (int i = 0; i < numBootstrapArguments; i++) {
1094       bootstrapMethodsAttribute.putShort(bootstrapMethodArgumentIndexes[i]);
1095     }
1096 
1097     // Compute the length and the hash code of the bootstrap method.
1098     int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset;
1099     int hashCode = bootstrapMethodHandle.hashCode();
1100     for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
1101       hashCode ^= bootstrapMethodArgument.hashCode();
1102     }
1103     hashCode &= 0x7FFFFFFF;
1104 
1105     // Add the bootstrap method to the symbol table or revert the above changes.
1106     return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode);
1107   }
1108 
1109   /**
1110    * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if
1111    * the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the
1112    * content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method).
1113    *
1114    * @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes.
1115    * @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes.
1116    * @param hashCode the hash code of this bootstrap method.
1117    * @return a new or already existing Symbol with the given value.
1118    */
addBootstrapMethod(final int offset, final int length, final int hashCode)1119   private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) {
1120     final byte[] bootstrapMethodsData = bootstrapMethods.data;
1121     Entry entry = get(hashCode);
1122     while (entry != null) {
1123       if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) {
1124         int otherOffset = (int) entry.data;
1125         boolean isSameBootstrapMethod = true;
1126         for (int i = 0; i < length; ++i) {
1127           if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) {
1128             isSameBootstrapMethod = false;
1129             break;
1130           }
1131         }
1132         if (isSameBootstrapMethod) {
1133           bootstrapMethods.length = offset; // Revert to old position.
1134           return entry;
1135         }
1136       }
1137       entry = entry.next;
1138     }
1139     return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode));
1140   }
1141 
1142   // -----------------------------------------------------------------------------------------------
1143   // Type table entries management.
1144   // -----------------------------------------------------------------------------------------------
1145 
1146   /**
1147    * Returns the type table element whose index is given.
1148    *
1149    * @param typeIndex a type table index.
1150    * @return the type table element whose index is given.
1151    */
getType(final int typeIndex)1152   Symbol getType(final int typeIndex) {
1153     return typeTable[typeIndex];
1154   }
1155 
1156   /**
1157    * Returns the label corresponding to the "forward uninitialized" type table element whose index
1158    * is given.
1159    *
1160    * @param typeIndex the type table index of a "forward uninitialized" type table element.
1161    * @return the label corresponding of the NEW instruction which created this "forward
1162    *     uninitialized" type.
1163    */
getForwardUninitializedLabel(final int typeIndex)1164   Label getForwardUninitializedLabel(final int typeIndex) {
1165     return labelTable[(int) typeTable[typeIndex].data].label;
1166   }
1167 
1168   /**
1169    * Adds a type in the type table of this symbol table. Does nothing if the type table already
1170    * contains a similar type.
1171    *
1172    * @param value an internal class name.
1173    * @return the index of a new or already existing type Symbol with the given value.
1174    */
addType(final String value)1175   int addType(final String value) {
1176     int hashCode = hash(Symbol.TYPE_TAG, value);
1177     Entry entry = get(hashCode);
1178     while (entry != null) {
1179       if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) {
1180         return entry.index;
1181       }
1182       entry = entry.next;
1183     }
1184     return addTypeInternal(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode));
1185   }
1186 
1187   /**
1188    * Adds an uninitialized type in the type table of this symbol table. Does nothing if the type
1189    * table already contains a similar type.
1190    *
1191    * @param value an internal class name.
1192    * @param bytecodeOffset the bytecode offset of the NEW instruction that created this
1193    *     uninitialized type value.
1194    * @return the index of a new or already existing type #@link Symbol} with the given value.
1195    */
addUninitializedType(final String value, final int bytecodeOffset)1196   int addUninitializedType(final String value, final int bytecodeOffset) {
1197     int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset);
1198     Entry entry = get(hashCode);
1199     while (entry != null) {
1200       if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG
1201           && entry.hashCode == hashCode
1202           && entry.data == bytecodeOffset
1203           && entry.value.equals(value)) {
1204         return entry.index;
1205       }
1206       entry = entry.next;
1207     }
1208     return addTypeInternal(
1209         new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode));
1210   }
1211 
1212   /**
1213    * Adds a "forward uninitialized" type in the type table of this symbol table. Does nothing if the
1214    * type table already contains a similar type.
1215    *
1216    * @param value an internal class name.
1217    * @param label the label of the NEW instruction that created this uninitialized type value. If
1218    *     the label is resolved, use the {@link #addUninitializedType} method instead.
1219    * @return the index of a new or already existing type {@link Symbol} with the given value.
1220    */
addForwardUninitializedType(final String value, final Label label)1221   int addForwardUninitializedType(final String value, final Label label) {
1222     int labelIndex = getOrAddLabelEntry(label).index;
1223     int hashCode = hash(Symbol.FORWARD_UNINITIALIZED_TYPE_TAG, value, labelIndex);
1224     Entry entry = get(hashCode);
1225     while (entry != null) {
1226       if (entry.tag == Symbol.FORWARD_UNINITIALIZED_TYPE_TAG
1227           && entry.hashCode == hashCode
1228           && entry.data == labelIndex
1229           && entry.value.equals(value)) {
1230         return entry.index;
1231       }
1232       entry = entry.next;
1233     }
1234     return addTypeInternal(
1235         new Entry(typeCount, Symbol.FORWARD_UNINITIALIZED_TYPE_TAG, value, labelIndex, hashCode));
1236   }
1237 
1238   /**
1239    * Adds a merged type in the type table of this symbol table. Does nothing if the type table
1240    * already contains a similar type.
1241    *
1242    * @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type
1243    *     table.
1244    * @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type
1245    *     table.
1246    * @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol,
1247    *     corresponding to the common super class of the given types.
1248    */
addMergedType(final int typeTableIndex1, final int typeTableIndex2)1249   int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
1250     long data =
1251         typeTableIndex1 < typeTableIndex2
1252             ? typeTableIndex1 | (((long) typeTableIndex2) << 32)
1253             : typeTableIndex2 | (((long) typeTableIndex1) << 32);
1254     int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2);
1255     Entry entry = get(hashCode);
1256     while (entry != null) {
1257       if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) {
1258         return entry.info;
1259       }
1260       entry = entry.next;
1261     }
1262     String type1 = typeTable[typeTableIndex1].value;
1263     String type2 = typeTable[typeTableIndex2].value;
1264     int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2));
1265     put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex;
1266     return commonSuperTypeIndex;
1267   }
1268 
1269   /**
1270    * Adds the given type Symbol to {@link #typeTable}.
1271    *
1272    * @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol.
1273    *     The index of this Symbol must be equal to the current value of {@link #typeCount}.
1274    * @return the index in {@link #typeTable} where the given type was added, which is also equal to
1275    *     entry's index by hypothesis.
1276    */
1277   private int addTypeInternal(final Entry entry) {
1278     if (typeTable == null) {
1279       typeTable = new Entry[16];
1280     }
1281     if (typeCount == typeTable.length) {
1282       Entry[] newTypeTable = new Entry[2 * typeTable.length];
1283       System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length);
1284       typeTable = newTypeTable;
1285     }
1286     typeTable[typeCount++] = entry;
1287     return put(entry).index;
1288   }
1289 
1290   /**
1291    * Returns the {@link LabelEntry} corresponding to the given label. Creates a new one if there is
1292    * no such entry.
1293    *
1294    * @param label the {@link Label} of a NEW instruction which created an uninitialized type, in the
1295    *     case where this NEW instruction is after the &lt;init&gt; constructor call (in bytecode
1296    *     offset order). See {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}.
1297    * @return the {@link LabelEntry} corresponding to {@code label}.
1298    */
1299   private LabelEntry getOrAddLabelEntry(final Label label) {
1300     if (labelEntries == null) {
1301       labelEntries = new LabelEntry[16];
1302       labelTable = new LabelEntry[16];
1303     }
1304     int hashCode = System.identityHashCode(label);
1305     LabelEntry labelEntry = labelEntries[hashCode % labelEntries.length];
1306     while (labelEntry != null && labelEntry.label != label) {
1307       labelEntry = labelEntry.next;
1308     }
1309     if (labelEntry != null) {
1310       return labelEntry;
1311     }
1312 
1313     if (labelCount > (labelEntries.length * 3) / 4) {
1314       int currentCapacity = labelEntries.length;
1315       int newCapacity = currentCapacity * 2 + 1;
1316       LabelEntry[] newLabelEntries = new LabelEntry[newCapacity];
1317       for (int i = currentCapacity - 1; i >= 0; --i) {
1318         LabelEntry currentEntry = labelEntries[i];
1319         while (currentEntry != null) {
1320           int newCurrentEntryIndex = System.identityHashCode(currentEntry.label) % newCapacity;
1321           LabelEntry nextEntry = currentEntry.next;
1322           currentEntry.next = newLabelEntries[newCurrentEntryIndex];
1323           newLabelEntries[newCurrentEntryIndex] = currentEntry;
1324           currentEntry = nextEntry;
1325         }
1326       }
1327       labelEntries = newLabelEntries;
1328     }
1329     if (labelCount == labelTable.length) {
1330       LabelEntry[] newLabelTable = new LabelEntry[2 * labelTable.length];
1331       System.arraycopy(labelTable, 0, newLabelTable, 0, labelTable.length);
1332       labelTable = newLabelTable;
1333     }
1334 
1335     labelEntry = new LabelEntry(labelCount, label);
1336     int index = hashCode % labelEntries.length;
1337     labelEntry.next = labelEntries[index];
1338     labelEntries[index] = labelEntry;
1339     labelTable[labelCount++] = labelEntry;
1340     return labelEntry;
1341   }
1342 
1343   // -----------------------------------------------------------------------------------------------
1344   // Static helper methods to compute hash codes.
1345   // -----------------------------------------------------------------------------------------------
1346 
1347   private static int hash(final int tag, final int value) {
1348     return 0x7FFFFFFF & (tag + value);
1349   }
1350 
1351   private static int hash(final int tag, final long value) {
1352     return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32));
1353   }
1354 
hash(final int tag, final String value)1355   private static int hash(final int tag, final String value) {
1356     return 0x7FFFFFFF & (tag + value.hashCode());
1357   }
1358 
hash(final int tag, final String value1, final int value2)1359   private static int hash(final int tag, final String value1, final int value2) {
1360     return 0x7FFFFFFF & (tag + value1.hashCode() + value2);
1361   }
1362 
hash(final int tag, final String value1, final String value2)1363   private static int hash(final int tag, final String value1, final String value2) {
1364     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode());
1365   }
1366 
hash( final int tag, final String value1, final String value2, final int value3)1367   private static int hash(
1368       final int tag, final String value1, final String value2, final int value3) {
1369     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1));
1370   }
1371 
hash( final int tag, final String value1, final String value2, final String value3)1372   private static int hash(
1373       final int tag, final String value1, final String value2, final String value3) {
1374     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode());
1375   }
1376 
hash( final int tag, final String value1, final String value2, final String value3, final int value4)1377   private static int hash(
1378       final int tag,
1379       final String value1,
1380       final String value2,
1381       final String value3,
1382       final int value4) {
1383     return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4);
1384   }
1385 
1386   /**
1387    * An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields
1388    * which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid
1389    * duplicate symbols). See {@link #entries}.
1390    *
1391    * @author Eric Bruneton
1392    */
1393   private static final class Entry extends Symbol {
1394 
1395     /** The hash code of this entry. */
1396     final int hashCode;
1397 
1398     /**
1399      * Another entry (and so on recursively) having the same hash code (modulo the size of {@link
1400      * #entries}) as this one.
1401      */
1402     Entry next;
1403 
Entry( final int index, final int tag, final String owner, final String name, final String value, final long data, final int hashCode)1404     Entry(
1405         final int index,
1406         final int tag,
1407         final String owner,
1408         final String name,
1409         final String value,
1410         final long data,
1411         final int hashCode) {
1412       super(index, tag, owner, name, value, data);
1413       this.hashCode = hashCode;
1414     }
1415 
Entry(final int index, final int tag, final String value, final int hashCode)1416     Entry(final int index, final int tag, final String value, final int hashCode) {
1417       super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0);
1418       this.hashCode = hashCode;
1419     }
1420 
Entry(final int index, final int tag, final String value, final long data, final int hashCode)1421     Entry(final int index, final int tag, final String value, final long data, final int hashCode) {
1422       super(index, tag, /* owner = */ null, /* name = */ null, value, data);
1423       this.hashCode = hashCode;
1424     }
1425 
Entry( final int index, final int tag, final String name, final String value, final int hashCode)1426     Entry(
1427         final int index, final int tag, final String name, final String value, final int hashCode) {
1428       super(index, tag, /* owner = */ null, name, value, /* data = */ 0);
1429       this.hashCode = hashCode;
1430     }
1431 
Entry(final int index, final int tag, final long data, final int hashCode)1432     Entry(final int index, final int tag, final long data, final int hashCode) {
1433       super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data);
1434       this.hashCode = hashCode;
1435     }
1436   }
1437 
1438   /**
1439    * A label corresponding to a "forward uninitialized" type in the ASM specific {@link
1440    * SymbolTable#typeTable} (see {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}).
1441    *
1442    * @author Eric Bruneton
1443    */
1444   private static final class LabelEntry {
1445 
1446     /** The index of this label entry in the {@link SymbolTable#labelTable} array. */
1447     final int index;
1448 
1449     /** The value of this label entry. */
1450     final Label label;
1451 
1452     /**
1453      * Another entry (and so on recursively) having the same hash code (modulo the size of {@link
1454      * SymbolTable#labelEntries}}) as this one.
1455      */
1456     LabelEntry next;
1457 
LabelEntry(final int index, final Label label)1458     LabelEntry(final int index, final Label label) {
1459       this.index = index;
1460       this.label = label;
1461     }
1462   }
1463 }
1464