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 <init> 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