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