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 import java.io.ByteArrayOutputStream; 31 import java.io.IOException; 32 import java.io.InputStream; 33 34 /** 35 * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java 36 * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the 37 * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode 38 * instruction encountered. 39 * 40 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a> 41 * @author Eric Bruneton 42 * @author Eugene Kuleshov 43 */ 44 public class ClassReader { 45 46 /** 47 * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed 48 * nor visited. 49 */ 50 public static final int SKIP_CODE = 1; 51 52 /** 53 * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, 54 * LocalVariableTypeTable, LineNumberTable and MethodParameters attributes. If this flag is set 55 * these attributes are neither parsed nor visited (i.e. {@link ClassVisitor#visitSource}, {@link 56 * MethodVisitor#visitLocalVariable}, {@link MethodVisitor#visitLineNumber} and {@link 57 * MethodVisitor#visitParameter} are not called). 58 */ 59 public static final int SKIP_DEBUG = 2; 60 61 /** 62 * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes 63 * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag 64 * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames 65 * that will be ignored and recomputed from scratch. 66 */ 67 public static final int SKIP_FRAMES = 4; 68 69 /** 70 * A flag to expand the stack map frames. By default stack map frames are visited in their 71 * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed" 72 * for the other classes). If this flag is set, stack map frames are always visited in expanded 73 * format (this option adds a decompression/compression step in ClassReader and ClassWriter which 74 * degrades performance quite a lot). 75 */ 76 public static final int EXPAND_FRAMES = 8; 77 78 /** 79 * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode 80 * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset 81 * reserved for it is not sufficient to store the bytecode offset. In this case the jump 82 * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes 83 * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing 84 * such instructions, in order to replace them with standard instructions. In addition, when this 85 * flag is used, goto_w and jsr_w are <i>not</i> converted into goto and jsr, to make sure that 86 * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a 87 * goto_w in ClassWriter cannot occur. 88 */ 89 static final int EXPAND_ASM_INSNS = 256; 90 91 /** The maximum size of array to allocate. */ 92 private static final int MAX_BUFFER_SIZE = 1024 * 1024; 93 94 /** The size of the temporary byte array used to read class input streams chunk by chunk. */ 95 private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; 96 97 /** 98 * A byte array containing the JVMS ClassFile structure to be parsed. 99 * 100 * @deprecated Use {@link #readByte(int)} and the other read methods instead. This field will 101 * eventually be deleted. 102 */ 103 @Deprecated 104 // DontCheck(MemberName): can't be renamed (for backward binary compatibility). 105 public final byte[] b; 106 107 /** The offset in bytes of the ClassFile's access_flags field. */ 108 public final int header; 109 110 /** 111 * A byte array containing the JVMS ClassFile structure to be parsed. <i>The content of this array 112 * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally 113 * not needed by class visitors.</i> 114 * 115 * <p>NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not 116 * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct 117 * ClassFile element offsets within this byte array. 118 */ 119 final byte[] classFileBuffer; 120 121 /** 122 * The offset in bytes, in {@link #classFileBuffer}, of each cp_info entry of the ClassFile's 123 * constant_pool array, <i>plus one</i>. In other words, the offset of constant pool entry i is 124 * given by cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - 125 * 1]. 126 */ 127 private final int[] cpInfoOffsets; 128 129 /** 130 * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids 131 * multiple parsing of a given CONSTANT_Utf8 constant pool item. 132 */ 133 private final String[] constantUtf8Values; 134 135 /** 136 * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This 137 * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item. 138 */ 139 private final ConstantDynamic[] constantDynamicValues; 140 141 /** 142 * The start offsets in {@link #classFileBuffer} of each element of the bootstrap_methods array 143 * (in the BootstrapMethods attribute). 144 * 145 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS 146 * 4.7.23</a> 147 */ 148 private final int[] bootstrapMethodOffsets; 149 150 /** 151 * A conservative estimate of the maximum length of the strings contained in the constant pool of 152 * the class. 153 */ 154 private final int maxStringLength; 155 156 // ----------------------------------------------------------------------------------------------- 157 // Constructors 158 // ----------------------------------------------------------------------------------------------- 159 160 /** 161 * Constructs a new {@link ClassReader} object. 162 * 163 * @param classFile the JVMS ClassFile structure to be read. 164 */ ClassReader(final byte[] classFile)165 public ClassReader(final byte[] classFile) { 166 this(classFile, 0, classFile.length); 167 } 168 169 /** 170 * Constructs a new {@link ClassReader} object. 171 * 172 * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. 173 * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. 174 * @param classFileLength the length in bytes of the ClassFile to be read. 175 */ ClassReader( final byte[] classFileBuffer, final int classFileOffset, final int classFileLength)176 public ClassReader( 177 final byte[] classFileBuffer, 178 final int classFileOffset, 179 final int classFileLength) { // NOPMD(UnusedFormalParameter) used for backward compatibility. 180 this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true); 181 } 182 183 /** 184 * Constructs a new {@link ClassReader} object. <i>This internal constructor must not be exposed 185 * as a public API</i>. 186 * 187 * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. 188 * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. 189 * @param checkClassVersion whether to check the class version or not. 190 */ 191 @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") ClassReader( final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion)192 ClassReader( 193 final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) { 194 this.classFileBuffer = classFileBuffer; 195 this.b = classFileBuffer; 196 // Check the class' major_version. This field is after the magic and minor_version fields, which 197 // use 4 and 2 bytes respectively. 198 if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V22) { 199 throw new IllegalArgumentException( 200 "Unsupported class file major version " + readShort(classFileOffset + 6)); 201 } 202 // Create the constant pool arrays. The constant_pool_count field is after the magic, 203 // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively. 204 int constantPoolCount = readUnsignedShort(classFileOffset + 8); 205 cpInfoOffsets = new int[constantPoolCount]; 206 constantUtf8Values = new String[constantPoolCount]; 207 // Compute the offset of each constant pool entry, as well as a conservative estimate of the 208 // maximum length of the constant pool strings. The first constant pool entry is after the 209 // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2 210 // bytes respectively. 211 int currentCpInfoIndex = 1; 212 int currentCpInfoOffset = classFileOffset + 10; 213 int currentMaxStringLength = 0; 214 boolean hasBootstrapMethods = false; 215 boolean hasConstantDynamic = false; 216 // The offset of the other entries depend on the total size of all the previous entries. 217 while (currentCpInfoIndex < constantPoolCount) { 218 cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1; 219 int cpInfoSize; 220 switch (classFileBuffer[currentCpInfoOffset]) { 221 case Symbol.CONSTANT_FIELDREF_TAG: 222 case Symbol.CONSTANT_METHODREF_TAG: 223 case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: 224 case Symbol.CONSTANT_INTEGER_TAG: 225 case Symbol.CONSTANT_FLOAT_TAG: 226 case Symbol.CONSTANT_NAME_AND_TYPE_TAG: 227 cpInfoSize = 5; 228 break; 229 case Symbol.CONSTANT_DYNAMIC_TAG: 230 cpInfoSize = 5; 231 hasBootstrapMethods = true; 232 hasConstantDynamic = true; 233 break; 234 case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: 235 cpInfoSize = 5; 236 hasBootstrapMethods = true; 237 break; 238 case Symbol.CONSTANT_LONG_TAG: 239 case Symbol.CONSTANT_DOUBLE_TAG: 240 cpInfoSize = 9; 241 currentCpInfoIndex++; 242 break; 243 case Symbol.CONSTANT_UTF8_TAG: 244 cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1); 245 if (cpInfoSize > currentMaxStringLength) { 246 // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate 247 // of the length in characters of the corresponding string, and is much cheaper to 248 // compute than this exact length. 249 currentMaxStringLength = cpInfoSize; 250 } 251 break; 252 case Symbol.CONSTANT_METHOD_HANDLE_TAG: 253 cpInfoSize = 4; 254 break; 255 case Symbol.CONSTANT_CLASS_TAG: 256 case Symbol.CONSTANT_STRING_TAG: 257 case Symbol.CONSTANT_METHOD_TYPE_TAG: 258 case Symbol.CONSTANT_PACKAGE_TAG: 259 case Symbol.CONSTANT_MODULE_TAG: 260 cpInfoSize = 3; 261 break; 262 default: 263 throw new IllegalArgumentException(); 264 } 265 currentCpInfoOffset += cpInfoSize; 266 } 267 maxStringLength = currentMaxStringLength; 268 // The Classfile's access_flags field is just after the last constant pool entry. 269 header = currentCpInfoOffset; 270 271 // Allocate the cache of ConstantDynamic values, if there is at least one. 272 constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null; 273 274 // Read the BootstrapMethods attribute, if any (only get the offset of each method). 275 bootstrapMethodOffsets = 276 hasBootstrapMethods ? readBootstrapMethodsAttribute(currentMaxStringLength) : null; 277 } 278 279 /** 280 * Constructs a new {@link ClassReader} object. 281 * 282 * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input 283 * stream must contain nothing more than the ClassFile structure itself. It is read from its 284 * current position to its end. 285 * @throws IOException if a problem occurs during reading. 286 */ ClassReader(final InputStream inputStream)287 public ClassReader(final InputStream inputStream) throws IOException { 288 this(readStream(inputStream, false)); 289 } 290 291 /** 292 * Constructs a new {@link ClassReader} object. 293 * 294 * @param className the fully qualified name of the class to be read. The ClassFile structure is 295 * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}. 296 * @throws IOException if an exception occurs during reading. 297 */ ClassReader(final String className)298 public ClassReader(final String className) throws IOException { 299 this( 300 readStream( 301 ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true)); 302 } 303 304 /** 305 * Reads the given input stream and returns its content as a byte array. 306 * 307 * @param inputStream an input stream. 308 * @param close true to close the input stream after reading. 309 * @return the content of the given input stream. 310 * @throws IOException if a problem occurs during reading. 311 */ 312 @SuppressWarnings("PMD.UseTryWithResources") readStream(final InputStream inputStream, final boolean close)313 private static byte[] readStream(final InputStream inputStream, final boolean close) 314 throws IOException { 315 if (inputStream == null) { 316 throw new IOException("Class not found"); 317 } 318 int bufferSize = computeBufferSize(inputStream); 319 try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { 320 byte[] data = new byte[bufferSize]; 321 int bytesRead; 322 int readCount = 0; 323 while ((bytesRead = inputStream.read(data, 0, bufferSize)) != -1) { 324 outputStream.write(data, 0, bytesRead); 325 readCount++; 326 } 327 outputStream.flush(); 328 if (readCount == 1) { 329 return data; 330 } 331 return outputStream.toByteArray(); 332 } finally { 333 if (close) { 334 inputStream.close(); 335 } 336 } 337 } 338 computeBufferSize(final InputStream inputStream)339 private static int computeBufferSize(final InputStream inputStream) throws IOException { 340 int expectedLength = inputStream.available(); 341 /* 342 * Some implementations can return 0 while holding available data (e.g. new 343 * FileInputStream("/proc/a_file")). Also in some pathological cases a very small number might 344 * be returned, and in this case we use a default size. 345 */ 346 if (expectedLength < 256) { 347 return INPUT_STREAM_DATA_CHUNK_SIZE; 348 } 349 return Math.min(expectedLength, MAX_BUFFER_SIZE); 350 } 351 352 // ----------------------------------------------------------------------------------------------- 353 // Accessors 354 // ----------------------------------------------------------------------------------------------- 355 356 /** 357 * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated 358 * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes. 359 * 360 * @return the class access flags. 361 * @see ClassVisitor#visit(int, int, String, String, String, String[]) 362 */ getAccess()363 public int getAccess() { 364 return readUnsignedShort(header); 365 } 366 367 /** 368 * Returns the internal name of the class (see {@link Type#getInternalName()}). 369 * 370 * @return the internal class name. 371 * @see ClassVisitor#visit(int, int, String, String, String, String[]) 372 */ getClassName()373 public String getClassName() { 374 // this_class is just after the access_flags field (using 2 bytes). 375 return readClass(header + 2, new char[maxStringLength]); 376 } 377 378 /** 379 * Returns the internal name of the super class (see {@link Type#getInternalName()}). For 380 * interfaces, the super class is {@link Object}. 381 * 382 * @return the internal name of the super class, or {@literal null} for {@link Object} class. 383 * @see ClassVisitor#visit(int, int, String, String, String, String[]) 384 */ getSuperName()385 public String getSuperName() { 386 // super_class is after the access_flags and this_class fields (2 bytes each). 387 return readClass(header + 4, new char[maxStringLength]); 388 } 389 390 /** 391 * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). 392 * 393 * @return the internal names of the directly implemented interfaces. Inherited implemented 394 * interfaces are not returned. 395 * @see ClassVisitor#visit(int, int, String, String, String, String[]) 396 */ getInterfaces()397 public String[] getInterfaces() { 398 // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). 399 int currentOffset = header + 6; 400 int interfacesCount = readUnsignedShort(currentOffset); 401 String[] interfaces = new String[interfacesCount]; 402 if (interfacesCount > 0) { 403 char[] charBuffer = new char[maxStringLength]; 404 for (int i = 0; i < interfacesCount; ++i) { 405 currentOffset += 2; 406 interfaces[i] = readClass(currentOffset, charBuffer); 407 } 408 } 409 return interfaces; 410 } 411 412 // ----------------------------------------------------------------------------------------------- 413 // Public methods 414 // ----------------------------------------------------------------------------------------------- 415 416 /** 417 * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this 418 * {@link ClassReader}. 419 * 420 * @param classVisitor the visitor that must visit this class. 421 * @param parsingOptions the options to use to parse this class. One or more of {@link 422 * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. 423 */ accept(final ClassVisitor classVisitor, final int parsingOptions)424 public void accept(final ClassVisitor classVisitor, final int parsingOptions) { 425 accept(classVisitor, new Attribute[0], parsingOptions); 426 } 427 428 /** 429 * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this 430 * {@link ClassReader}. 431 * 432 * @param classVisitor the visitor that must visit this class. 433 * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of 434 * the class. Any attribute whose type is not equal to the type of one the prototypes will not 435 * be parsed: its byte array value will be passed unchanged to the ClassWriter. <i>This may 436 * corrupt it if this value contains references to the constant pool, or has syntactic or 437 * semantic links with a class element that has been transformed by a class adapter between 438 * the reader and the writer</i>. 439 * @param parsingOptions the options to use to parse this class. One or more of {@link 440 * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. 441 */ accept( final ClassVisitor classVisitor, final Attribute[] attributePrototypes, final int parsingOptions)442 public void accept( 443 final ClassVisitor classVisitor, 444 final Attribute[] attributePrototypes, 445 final int parsingOptions) { 446 Context context = new Context(); 447 context.attributePrototypes = attributePrototypes; 448 context.parsingOptions = parsingOptions; 449 context.charBuffer = new char[maxStringLength]; 450 451 // Read the access_flags, this_class, super_class, interface_count and interfaces fields. 452 char[] charBuffer = context.charBuffer; 453 int currentOffset = header; 454 int accessFlags = readUnsignedShort(currentOffset); 455 String thisClass = readClass(currentOffset + 2, charBuffer); 456 String superClass = readClass(currentOffset + 4, charBuffer); 457 String[] interfaces = new String[readUnsignedShort(currentOffset + 6)]; 458 currentOffset += 8; 459 for (int i = 0; i < interfaces.length; ++i) { 460 interfaces[i] = readClass(currentOffset, charBuffer); 461 currentOffset += 2; 462 } 463 464 // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS). 465 // Attribute offsets exclude the attribute_name_index and attribute_length fields. 466 // - The offset of the InnerClasses attribute, or 0. 467 int innerClassesOffset = 0; 468 // - The offset of the EnclosingMethod attribute, or 0. 469 int enclosingMethodOffset = 0; 470 // - The string corresponding to the Signature attribute, or null. 471 String signature = null; 472 // - The string corresponding to the SourceFile attribute, or null. 473 String sourceFile = null; 474 // - The string corresponding to the SourceDebugExtension attribute, or null. 475 String sourceDebugExtension = null; 476 // - The offset of the RuntimeVisibleAnnotations attribute, or 0. 477 int runtimeVisibleAnnotationsOffset = 0; 478 // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. 479 int runtimeInvisibleAnnotationsOffset = 0; 480 // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. 481 int runtimeVisibleTypeAnnotationsOffset = 0; 482 // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. 483 int runtimeInvisibleTypeAnnotationsOffset = 0; 484 // - The offset of the Module attribute, or 0. 485 int moduleOffset = 0; 486 // - The offset of the ModulePackages attribute, or 0. 487 int modulePackagesOffset = 0; 488 // - The string corresponding to the ModuleMainClass attribute, or null. 489 String moduleMainClass = null; 490 // - The string corresponding to the NestHost attribute, or null. 491 String nestHostClass = null; 492 // - The offset of the NestMembers attribute, or 0. 493 int nestMembersOffset = 0; 494 // - The offset of the PermittedSubclasses attribute, or 0 495 int permittedSubclassesOffset = 0; 496 // - The offset of the Record attribute, or 0. 497 int recordOffset = 0; 498 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). 499 // This list in the <i>reverse order</i> or their order in the ClassFile structure. 500 Attribute attributes = null; 501 502 int currentAttributeOffset = getFirstAttributeOffset(); 503 for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { 504 // Read the attribute_info's attribute_name and attribute_length fields. 505 String attributeName = readUTF8(currentAttributeOffset, charBuffer); 506 int attributeLength = readInt(currentAttributeOffset + 2); 507 currentAttributeOffset += 6; 508 // The tests are sorted in decreasing frequency order (based on frequencies observed on 509 // typical classes). 510 if (Constants.SOURCE_FILE.equals(attributeName)) { 511 sourceFile = readUTF8(currentAttributeOffset, charBuffer); 512 } else if (Constants.INNER_CLASSES.equals(attributeName)) { 513 innerClassesOffset = currentAttributeOffset; 514 } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) { 515 enclosingMethodOffset = currentAttributeOffset; 516 } else if (Constants.NEST_HOST.equals(attributeName)) { 517 nestHostClass = readClass(currentAttributeOffset, charBuffer); 518 } else if (Constants.NEST_MEMBERS.equals(attributeName)) { 519 nestMembersOffset = currentAttributeOffset; 520 } else if (Constants.PERMITTED_SUBCLASSES.equals(attributeName)) { 521 permittedSubclassesOffset = currentAttributeOffset; 522 } else if (Constants.SIGNATURE.equals(attributeName)) { 523 signature = readUTF8(currentAttributeOffset, charBuffer); 524 } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { 525 runtimeVisibleAnnotationsOffset = currentAttributeOffset; 526 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 527 runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset; 528 } else if (Constants.DEPRECATED.equals(attributeName)) { 529 accessFlags |= Opcodes.ACC_DEPRECATED; 530 } else if (Constants.SYNTHETIC.equals(attributeName)) { 531 accessFlags |= Opcodes.ACC_SYNTHETIC; 532 } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { 533 if (attributeLength > classFileBuffer.length - currentAttributeOffset) { 534 throw new IllegalArgumentException(); 535 } 536 sourceDebugExtension = 537 readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]); 538 } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { 539 runtimeInvisibleAnnotationsOffset = currentAttributeOffset; 540 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 541 runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset; 542 } else if (Constants.RECORD.equals(attributeName)) { 543 recordOffset = currentAttributeOffset; 544 accessFlags |= Opcodes.ACC_RECORD; 545 } else if (Constants.MODULE.equals(attributeName)) { 546 moduleOffset = currentAttributeOffset; 547 } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) { 548 moduleMainClass = readClass(currentAttributeOffset, charBuffer); 549 } else if (Constants.MODULE_PACKAGES.equals(attributeName)) { 550 modulePackagesOffset = currentAttributeOffset; 551 } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) { 552 // The BootstrapMethods attribute is read in the constructor. 553 Attribute attribute = 554 readAttribute( 555 attributePrototypes, 556 attributeName, 557 currentAttributeOffset, 558 attributeLength, 559 charBuffer, 560 -1, 561 null); 562 attribute.nextAttribute = attributes; 563 attributes = attribute; 564 } 565 currentAttributeOffset += attributeLength; 566 } 567 568 // Visit the class declaration. The minor_version and major_version fields start 6 bytes before 569 // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition). 570 classVisitor.visit( 571 readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces); 572 573 // Visit the SourceFile and SourceDebugExtenstion attributes. 574 if ((parsingOptions & SKIP_DEBUG) == 0 575 && (sourceFile != null || sourceDebugExtension != null)) { 576 classVisitor.visitSource(sourceFile, sourceDebugExtension); 577 } 578 579 // Visit the Module, ModulePackages and ModuleMainClass attributes. 580 if (moduleOffset != 0) { 581 readModuleAttributes( 582 classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass); 583 } 584 585 // Visit the NestHost attribute. 586 if (nestHostClass != null) { 587 classVisitor.visitNestHost(nestHostClass); 588 } 589 590 // Visit the EnclosingMethod attribute. 591 if (enclosingMethodOffset != 0) { 592 String className = readClass(enclosingMethodOffset, charBuffer); 593 int methodIndex = readUnsignedShort(enclosingMethodOffset + 2); 594 String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer); 595 String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer); 596 classVisitor.visitOuterClass(className, name, type); 597 } 598 599 // Visit the RuntimeVisibleAnnotations attribute. 600 if (runtimeVisibleAnnotationsOffset != 0) { 601 int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); 602 int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; 603 while (numAnnotations-- > 0) { 604 // Parse the type_index field. 605 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 606 currentAnnotationOffset += 2; 607 // Parse num_element_value_pairs and element_value_pairs and visit these values. 608 currentAnnotationOffset = 609 readElementValues( 610 classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), 611 currentAnnotationOffset, 612 /* named = */ true, 613 charBuffer); 614 } 615 } 616 617 // Visit the RuntimeInvisibleAnnotations attribute. 618 if (runtimeInvisibleAnnotationsOffset != 0) { 619 int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); 620 int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; 621 while (numAnnotations-- > 0) { 622 // Parse the type_index field. 623 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 624 currentAnnotationOffset += 2; 625 // Parse num_element_value_pairs and element_value_pairs and visit these values. 626 currentAnnotationOffset = 627 readElementValues( 628 classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), 629 currentAnnotationOffset, 630 /* named = */ true, 631 charBuffer); 632 } 633 } 634 635 // Visit the RuntimeVisibleTypeAnnotations attribute. 636 if (runtimeVisibleTypeAnnotationsOffset != 0) { 637 int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); 638 int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; 639 while (numAnnotations-- > 0) { 640 // Parse the target_type, target_info and target_path fields. 641 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 642 // Parse the type_index field. 643 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 644 currentAnnotationOffset += 2; 645 // Parse num_element_value_pairs and element_value_pairs and visit these values. 646 currentAnnotationOffset = 647 readElementValues( 648 classVisitor.visitTypeAnnotation( 649 context.currentTypeAnnotationTarget, 650 context.currentTypeAnnotationTargetPath, 651 annotationDescriptor, 652 /* visible = */ true), 653 currentAnnotationOffset, 654 /* named = */ true, 655 charBuffer); 656 } 657 } 658 659 // Visit the RuntimeInvisibleTypeAnnotations attribute. 660 if (runtimeInvisibleTypeAnnotationsOffset != 0) { 661 int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); 662 int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; 663 while (numAnnotations-- > 0) { 664 // Parse the target_type, target_info and target_path fields. 665 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 666 // Parse the type_index field. 667 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 668 currentAnnotationOffset += 2; 669 // Parse num_element_value_pairs and element_value_pairs and visit these values. 670 currentAnnotationOffset = 671 readElementValues( 672 classVisitor.visitTypeAnnotation( 673 context.currentTypeAnnotationTarget, 674 context.currentTypeAnnotationTargetPath, 675 annotationDescriptor, 676 /* visible = */ false), 677 currentAnnotationOffset, 678 /* named = */ true, 679 charBuffer); 680 } 681 } 682 683 // Visit the non standard attributes. 684 while (attributes != null) { 685 // Copy and reset the nextAttribute field so that it can also be used in ClassWriter. 686 Attribute nextAttribute = attributes.nextAttribute; 687 attributes.nextAttribute = null; 688 classVisitor.visitAttribute(attributes); 689 attributes = nextAttribute; 690 } 691 692 // Visit the NestedMembers attribute. 693 if (nestMembersOffset != 0) { 694 int numberOfNestMembers = readUnsignedShort(nestMembersOffset); 695 int currentNestMemberOffset = nestMembersOffset + 2; 696 while (numberOfNestMembers-- > 0) { 697 classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer)); 698 currentNestMemberOffset += 2; 699 } 700 } 701 702 // Visit the PermittedSubclasses attribute. 703 if (permittedSubclassesOffset != 0) { 704 int numberOfPermittedSubclasses = readUnsignedShort(permittedSubclassesOffset); 705 int currentPermittedSubclassesOffset = permittedSubclassesOffset + 2; 706 while (numberOfPermittedSubclasses-- > 0) { 707 classVisitor.visitPermittedSubclass( 708 readClass(currentPermittedSubclassesOffset, charBuffer)); 709 currentPermittedSubclassesOffset += 2; 710 } 711 } 712 713 // Visit the InnerClasses attribute. 714 if (innerClassesOffset != 0) { 715 int numberOfClasses = readUnsignedShort(innerClassesOffset); 716 int currentClassesOffset = innerClassesOffset + 2; 717 while (numberOfClasses-- > 0) { 718 classVisitor.visitInnerClass( 719 readClass(currentClassesOffset, charBuffer), 720 readClass(currentClassesOffset + 2, charBuffer), 721 readUTF8(currentClassesOffset + 4, charBuffer), 722 readUnsignedShort(currentClassesOffset + 6)); 723 currentClassesOffset += 8; 724 } 725 } 726 727 // Visit Record components. 728 if (recordOffset != 0) { 729 int recordComponentsCount = readUnsignedShort(recordOffset); 730 recordOffset += 2; 731 while (recordComponentsCount-- > 0) { 732 recordOffset = readRecordComponent(classVisitor, context, recordOffset); 733 } 734 } 735 736 // Visit the fields and methods. 737 int fieldsCount = readUnsignedShort(currentOffset); 738 currentOffset += 2; 739 while (fieldsCount-- > 0) { 740 currentOffset = readField(classVisitor, context, currentOffset); 741 } 742 int methodsCount = readUnsignedShort(currentOffset); 743 currentOffset += 2; 744 while (methodsCount-- > 0) { 745 currentOffset = readMethod(classVisitor, context, currentOffset); 746 } 747 748 // Visit the end of the class. 749 classVisitor.visitEnd(); 750 } 751 752 // ---------------------------------------------------------------------------------------------- 753 // Methods to parse modules, fields and methods 754 // ---------------------------------------------------------------------------------------------- 755 756 /** 757 * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them. 758 * 759 * @param classVisitor the current class visitor 760 * @param context information about the class being parsed. 761 * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's 762 * attribute_name_index and attribute_length fields). 763 * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the 764 * attribute_info's attribute_name_index and attribute_length fields), or 0. 765 * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or {@literal 766 * null}. 767 */ readModuleAttributes( final ClassVisitor classVisitor, final Context context, final int moduleOffset, final int modulePackagesOffset, final String moduleMainClass)768 private void readModuleAttributes( 769 final ClassVisitor classVisitor, 770 final Context context, 771 final int moduleOffset, 772 final int modulePackagesOffset, 773 final String moduleMainClass) { 774 char[] buffer = context.charBuffer; 775 776 // Read the module_name_index, module_flags and module_version_index fields and visit them. 777 int currentOffset = moduleOffset; 778 String moduleName = readModule(currentOffset, buffer); 779 int moduleFlags = readUnsignedShort(currentOffset + 2); 780 String moduleVersion = readUTF8(currentOffset + 4, buffer); 781 currentOffset += 6; 782 ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion); 783 if (moduleVisitor == null) { 784 return; 785 } 786 787 // Visit the ModuleMainClass attribute. 788 if (moduleMainClass != null) { 789 moduleVisitor.visitMainClass(moduleMainClass); 790 } 791 792 // Visit the ModulePackages attribute. 793 if (modulePackagesOffset != 0) { 794 int packageCount = readUnsignedShort(modulePackagesOffset); 795 int currentPackageOffset = modulePackagesOffset + 2; 796 while (packageCount-- > 0) { 797 moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer)); 798 currentPackageOffset += 2; 799 } 800 } 801 802 // Read the 'requires_count' and 'requires' fields. 803 int requiresCount = readUnsignedShort(currentOffset); 804 currentOffset += 2; 805 while (requiresCount-- > 0) { 806 // Read the requires_index, requires_flags and requires_version fields and visit them. 807 String requires = readModule(currentOffset, buffer); 808 int requiresFlags = readUnsignedShort(currentOffset + 2); 809 String requiresVersion = readUTF8(currentOffset + 4, buffer); 810 currentOffset += 6; 811 moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion); 812 } 813 814 // Read the 'exports_count' and 'exports' fields. 815 int exportsCount = readUnsignedShort(currentOffset); 816 currentOffset += 2; 817 while (exportsCount-- > 0) { 818 // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields 819 // and visit them. 820 String exports = readPackage(currentOffset, buffer); 821 int exportsFlags = readUnsignedShort(currentOffset + 2); 822 int exportsToCount = readUnsignedShort(currentOffset + 4); 823 currentOffset += 6; 824 String[] exportsTo = null; 825 if (exportsToCount != 0) { 826 exportsTo = new String[exportsToCount]; 827 for (int i = 0; i < exportsToCount; ++i) { 828 exportsTo[i] = readModule(currentOffset, buffer); 829 currentOffset += 2; 830 } 831 } 832 moduleVisitor.visitExport(exports, exportsFlags, exportsTo); 833 } 834 835 // Reads the 'opens_count' and 'opens' fields. 836 int opensCount = readUnsignedShort(currentOffset); 837 currentOffset += 2; 838 while (opensCount-- > 0) { 839 // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them. 840 String opens = readPackage(currentOffset, buffer); 841 int opensFlags = readUnsignedShort(currentOffset + 2); 842 int opensToCount = readUnsignedShort(currentOffset + 4); 843 currentOffset += 6; 844 String[] opensTo = null; 845 if (opensToCount != 0) { 846 opensTo = new String[opensToCount]; 847 for (int i = 0; i < opensToCount; ++i) { 848 opensTo[i] = readModule(currentOffset, buffer); 849 currentOffset += 2; 850 } 851 } 852 moduleVisitor.visitOpen(opens, opensFlags, opensTo); 853 } 854 855 // Read the 'uses_count' and 'uses' fields. 856 int usesCount = readUnsignedShort(currentOffset); 857 currentOffset += 2; 858 while (usesCount-- > 0) { 859 moduleVisitor.visitUse(readClass(currentOffset, buffer)); 860 currentOffset += 2; 861 } 862 863 // Read the 'provides_count' and 'provides' fields. 864 int providesCount = readUnsignedShort(currentOffset); 865 currentOffset += 2; 866 while (providesCount-- > 0) { 867 // Read the provides_index, provides_with_count and provides_with_index fields and visit them. 868 String provides = readClass(currentOffset, buffer); 869 int providesWithCount = readUnsignedShort(currentOffset + 2); 870 currentOffset += 4; 871 String[] providesWith = new String[providesWithCount]; 872 for (int i = 0; i < providesWithCount; ++i) { 873 providesWith[i] = readClass(currentOffset, buffer); 874 currentOffset += 2; 875 } 876 moduleVisitor.visitProvide(provides, providesWith); 877 } 878 879 // Visit the end of the module attributes. 880 moduleVisitor.visitEnd(); 881 } 882 883 /** 884 * Reads a record component and visit it. 885 * 886 * @param classVisitor the current class visitor 887 * @param context information about the class being parsed. 888 * @param recordComponentOffset the offset of the current record component. 889 * @return the offset of the first byte following the record component. 890 */ readRecordComponent( final ClassVisitor classVisitor, final Context context, final int recordComponentOffset)891 private int readRecordComponent( 892 final ClassVisitor classVisitor, final Context context, final int recordComponentOffset) { 893 char[] charBuffer = context.charBuffer; 894 895 int currentOffset = recordComponentOffset; 896 String name = readUTF8(currentOffset, charBuffer); 897 String descriptor = readUTF8(currentOffset + 2, charBuffer); 898 currentOffset += 4; 899 900 // Read the record component attributes (the variables are ordered as in Section 4.7 of the 901 // JVMS). 902 903 // Attribute offsets exclude the attribute_name_index and attribute_length fields. 904 // - The string corresponding to the Signature attribute, or null. 905 String signature = null; 906 // - The offset of the RuntimeVisibleAnnotations attribute, or 0. 907 int runtimeVisibleAnnotationsOffset = 0; 908 // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. 909 int runtimeInvisibleAnnotationsOffset = 0; 910 // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. 911 int runtimeVisibleTypeAnnotationsOffset = 0; 912 // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. 913 int runtimeInvisibleTypeAnnotationsOffset = 0; 914 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). 915 // This list in the <i>reverse order</i> or their order in the ClassFile structure. 916 Attribute attributes = null; 917 918 int attributesCount = readUnsignedShort(currentOffset); 919 currentOffset += 2; 920 while (attributesCount-- > 0) { 921 // Read the attribute_info's attribute_name and attribute_length fields. 922 String attributeName = readUTF8(currentOffset, charBuffer); 923 int attributeLength = readInt(currentOffset + 2); 924 currentOffset += 6; 925 // The tests are sorted in decreasing frequency order (based on frequencies observed on 926 // typical classes). 927 if (Constants.SIGNATURE.equals(attributeName)) { 928 signature = readUTF8(currentOffset, charBuffer); 929 } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { 930 runtimeVisibleAnnotationsOffset = currentOffset; 931 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 932 runtimeVisibleTypeAnnotationsOffset = currentOffset; 933 } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { 934 runtimeInvisibleAnnotationsOffset = currentOffset; 935 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 936 runtimeInvisibleTypeAnnotationsOffset = currentOffset; 937 } else { 938 Attribute attribute = 939 readAttribute( 940 context.attributePrototypes, 941 attributeName, 942 currentOffset, 943 attributeLength, 944 charBuffer, 945 -1, 946 null); 947 attribute.nextAttribute = attributes; 948 attributes = attribute; 949 } 950 currentOffset += attributeLength; 951 } 952 953 RecordComponentVisitor recordComponentVisitor = 954 classVisitor.visitRecordComponent(name, descriptor, signature); 955 if (recordComponentVisitor == null) { 956 return currentOffset; 957 } 958 959 // Visit the RuntimeVisibleAnnotations attribute. 960 if (runtimeVisibleAnnotationsOffset != 0) { 961 int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); 962 int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; 963 while (numAnnotations-- > 0) { 964 // Parse the type_index field. 965 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 966 currentAnnotationOffset += 2; 967 // Parse num_element_value_pairs and element_value_pairs and visit these values. 968 currentAnnotationOffset = 969 readElementValues( 970 recordComponentVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), 971 currentAnnotationOffset, 972 /* named = */ true, 973 charBuffer); 974 } 975 } 976 977 // Visit the RuntimeInvisibleAnnotations attribute. 978 if (runtimeInvisibleAnnotationsOffset != 0) { 979 int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); 980 int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; 981 while (numAnnotations-- > 0) { 982 // Parse the type_index field. 983 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 984 currentAnnotationOffset += 2; 985 // Parse num_element_value_pairs and element_value_pairs and visit these values. 986 currentAnnotationOffset = 987 readElementValues( 988 recordComponentVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), 989 currentAnnotationOffset, 990 /* named = */ true, 991 charBuffer); 992 } 993 } 994 995 // Visit the RuntimeVisibleTypeAnnotations attribute. 996 if (runtimeVisibleTypeAnnotationsOffset != 0) { 997 int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); 998 int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; 999 while (numAnnotations-- > 0) { 1000 // Parse the target_type, target_info and target_path fields. 1001 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 1002 // Parse the type_index field. 1003 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1004 currentAnnotationOffset += 2; 1005 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1006 currentAnnotationOffset = 1007 readElementValues( 1008 recordComponentVisitor.visitTypeAnnotation( 1009 context.currentTypeAnnotationTarget, 1010 context.currentTypeAnnotationTargetPath, 1011 annotationDescriptor, 1012 /* visible = */ true), 1013 currentAnnotationOffset, 1014 /* named = */ true, 1015 charBuffer); 1016 } 1017 } 1018 1019 // Visit the RuntimeInvisibleTypeAnnotations attribute. 1020 if (runtimeInvisibleTypeAnnotationsOffset != 0) { 1021 int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); 1022 int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; 1023 while (numAnnotations-- > 0) { 1024 // Parse the target_type, target_info and target_path fields. 1025 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 1026 // Parse the type_index field. 1027 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1028 currentAnnotationOffset += 2; 1029 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1030 currentAnnotationOffset = 1031 readElementValues( 1032 recordComponentVisitor.visitTypeAnnotation( 1033 context.currentTypeAnnotationTarget, 1034 context.currentTypeAnnotationTargetPath, 1035 annotationDescriptor, 1036 /* visible = */ false), 1037 currentAnnotationOffset, 1038 /* named = */ true, 1039 charBuffer); 1040 } 1041 } 1042 1043 // Visit the non standard attributes. 1044 while (attributes != null) { 1045 // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. 1046 Attribute nextAttribute = attributes.nextAttribute; 1047 attributes.nextAttribute = null; 1048 recordComponentVisitor.visitAttribute(attributes); 1049 attributes = nextAttribute; 1050 } 1051 1052 // Visit the end of the field. 1053 recordComponentVisitor.visitEnd(); 1054 return currentOffset; 1055 } 1056 1057 /** 1058 * Reads a JVMS field_info structure and makes the given visitor visit it. 1059 * 1060 * @param classVisitor the visitor that must visit the field. 1061 * @param context information about the class being parsed. 1062 * @param fieldInfoOffset the start offset of the field_info structure. 1063 * @return the offset of the first byte following the field_info structure. 1064 */ readField( final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset)1065 private int readField( 1066 final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) { 1067 char[] charBuffer = context.charBuffer; 1068 1069 // Read the access_flags, name_index and descriptor_index fields. 1070 int currentOffset = fieldInfoOffset; 1071 int accessFlags = readUnsignedShort(currentOffset); 1072 String name = readUTF8(currentOffset + 2, charBuffer); 1073 String descriptor = readUTF8(currentOffset + 4, charBuffer); 1074 currentOffset += 6; 1075 1076 // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS). 1077 // Attribute offsets exclude the attribute_name_index and attribute_length fields. 1078 // - The value corresponding to the ConstantValue attribute, or null. 1079 Object constantValue = null; 1080 // - The string corresponding to the Signature attribute, or null. 1081 String signature = null; 1082 // - The offset of the RuntimeVisibleAnnotations attribute, or 0. 1083 int runtimeVisibleAnnotationsOffset = 0; 1084 // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. 1085 int runtimeInvisibleAnnotationsOffset = 0; 1086 // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. 1087 int runtimeVisibleTypeAnnotationsOffset = 0; 1088 // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. 1089 int runtimeInvisibleTypeAnnotationsOffset = 0; 1090 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). 1091 // This list in the <i>reverse order</i> or their order in the ClassFile structure. 1092 Attribute attributes = null; 1093 1094 int attributesCount = readUnsignedShort(currentOffset); 1095 currentOffset += 2; 1096 while (attributesCount-- > 0) { 1097 // Read the attribute_info's attribute_name and attribute_length fields. 1098 String attributeName = readUTF8(currentOffset, charBuffer); 1099 int attributeLength = readInt(currentOffset + 2); 1100 currentOffset += 6; 1101 // The tests are sorted in decreasing frequency order (based on frequencies observed on 1102 // typical classes). 1103 if (Constants.CONSTANT_VALUE.equals(attributeName)) { 1104 int constantvalueIndex = readUnsignedShort(currentOffset); 1105 constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer); 1106 } else if (Constants.SIGNATURE.equals(attributeName)) { 1107 signature = readUTF8(currentOffset, charBuffer); 1108 } else if (Constants.DEPRECATED.equals(attributeName)) { 1109 accessFlags |= Opcodes.ACC_DEPRECATED; 1110 } else if (Constants.SYNTHETIC.equals(attributeName)) { 1111 accessFlags |= Opcodes.ACC_SYNTHETIC; 1112 } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { 1113 runtimeVisibleAnnotationsOffset = currentOffset; 1114 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 1115 runtimeVisibleTypeAnnotationsOffset = currentOffset; 1116 } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { 1117 runtimeInvisibleAnnotationsOffset = currentOffset; 1118 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 1119 runtimeInvisibleTypeAnnotationsOffset = currentOffset; 1120 } else { 1121 Attribute attribute = 1122 readAttribute( 1123 context.attributePrototypes, 1124 attributeName, 1125 currentOffset, 1126 attributeLength, 1127 charBuffer, 1128 -1, 1129 null); 1130 attribute.nextAttribute = attributes; 1131 attributes = attribute; 1132 } 1133 currentOffset += attributeLength; 1134 } 1135 1136 // Visit the field declaration. 1137 FieldVisitor fieldVisitor = 1138 classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue); 1139 if (fieldVisitor == null) { 1140 return currentOffset; 1141 } 1142 1143 // Visit the RuntimeVisibleAnnotations attribute. 1144 if (runtimeVisibleAnnotationsOffset != 0) { 1145 int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); 1146 int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; 1147 while (numAnnotations-- > 0) { 1148 // Parse the type_index field. 1149 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1150 currentAnnotationOffset += 2; 1151 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1152 currentAnnotationOffset = 1153 readElementValues( 1154 fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), 1155 currentAnnotationOffset, 1156 /* named = */ true, 1157 charBuffer); 1158 } 1159 } 1160 1161 // Visit the RuntimeInvisibleAnnotations attribute. 1162 if (runtimeInvisibleAnnotationsOffset != 0) { 1163 int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); 1164 int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; 1165 while (numAnnotations-- > 0) { 1166 // Parse the type_index field. 1167 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1168 currentAnnotationOffset += 2; 1169 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1170 currentAnnotationOffset = 1171 readElementValues( 1172 fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), 1173 currentAnnotationOffset, 1174 /* named = */ true, 1175 charBuffer); 1176 } 1177 } 1178 1179 // Visit the RuntimeVisibleTypeAnnotations attribute. 1180 if (runtimeVisibleTypeAnnotationsOffset != 0) { 1181 int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); 1182 int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; 1183 while (numAnnotations-- > 0) { 1184 // Parse the target_type, target_info and target_path fields. 1185 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 1186 // Parse the type_index field. 1187 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1188 currentAnnotationOffset += 2; 1189 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1190 currentAnnotationOffset = 1191 readElementValues( 1192 fieldVisitor.visitTypeAnnotation( 1193 context.currentTypeAnnotationTarget, 1194 context.currentTypeAnnotationTargetPath, 1195 annotationDescriptor, 1196 /* visible = */ true), 1197 currentAnnotationOffset, 1198 /* named = */ true, 1199 charBuffer); 1200 } 1201 } 1202 1203 // Visit the RuntimeInvisibleTypeAnnotations attribute. 1204 if (runtimeInvisibleTypeAnnotationsOffset != 0) { 1205 int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); 1206 int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; 1207 while (numAnnotations-- > 0) { 1208 // Parse the target_type, target_info and target_path fields. 1209 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 1210 // Parse the type_index field. 1211 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1212 currentAnnotationOffset += 2; 1213 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1214 currentAnnotationOffset = 1215 readElementValues( 1216 fieldVisitor.visitTypeAnnotation( 1217 context.currentTypeAnnotationTarget, 1218 context.currentTypeAnnotationTargetPath, 1219 annotationDescriptor, 1220 /* visible = */ false), 1221 currentAnnotationOffset, 1222 /* named = */ true, 1223 charBuffer); 1224 } 1225 } 1226 1227 // Visit the non standard attributes. 1228 while (attributes != null) { 1229 // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. 1230 Attribute nextAttribute = attributes.nextAttribute; 1231 attributes.nextAttribute = null; 1232 fieldVisitor.visitAttribute(attributes); 1233 attributes = nextAttribute; 1234 } 1235 1236 // Visit the end of the field. 1237 fieldVisitor.visitEnd(); 1238 return currentOffset; 1239 } 1240 1241 /** 1242 * Reads a JVMS method_info structure and makes the given visitor visit it. 1243 * 1244 * @param classVisitor the visitor that must visit the method. 1245 * @param context information about the class being parsed. 1246 * @param methodInfoOffset the start offset of the method_info structure. 1247 * @return the offset of the first byte following the method_info structure. 1248 */ readMethod( final ClassVisitor classVisitor, final Context context, final int methodInfoOffset)1249 private int readMethod( 1250 final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) { 1251 char[] charBuffer = context.charBuffer; 1252 1253 // Read the access_flags, name_index and descriptor_index fields. 1254 int currentOffset = methodInfoOffset; 1255 context.currentMethodAccessFlags = readUnsignedShort(currentOffset); 1256 context.currentMethodName = readUTF8(currentOffset + 2, charBuffer); 1257 context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer); 1258 currentOffset += 6; 1259 1260 // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS). 1261 // Attribute offsets exclude the attribute_name_index and attribute_length fields. 1262 // - The offset of the Code attribute, or 0. 1263 int codeOffset = 0; 1264 // - The offset of the Exceptions attribute, or 0. 1265 int exceptionsOffset = 0; 1266 // - The strings corresponding to the Exceptions attribute, or null. 1267 String[] exceptions = null; 1268 // - Whether the method has a Synthetic attribute. 1269 boolean synthetic = false; 1270 // - The constant pool index contained in the Signature attribute, or 0. 1271 int signatureIndex = 0; 1272 // - The offset of the RuntimeVisibleAnnotations attribute, or 0. 1273 int runtimeVisibleAnnotationsOffset = 0; 1274 // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. 1275 int runtimeInvisibleAnnotationsOffset = 0; 1276 // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0. 1277 int runtimeVisibleParameterAnnotationsOffset = 0; 1278 // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0. 1279 int runtimeInvisibleParameterAnnotationsOffset = 0; 1280 // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. 1281 int runtimeVisibleTypeAnnotationsOffset = 0; 1282 // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. 1283 int runtimeInvisibleTypeAnnotationsOffset = 0; 1284 // - The offset of the AnnotationDefault attribute, or 0. 1285 int annotationDefaultOffset = 0; 1286 // - The offset of the MethodParameters attribute, or 0. 1287 int methodParametersOffset = 0; 1288 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). 1289 // This list in the <i>reverse order</i> or their order in the ClassFile structure. 1290 Attribute attributes = null; 1291 1292 int attributesCount = readUnsignedShort(currentOffset); 1293 currentOffset += 2; 1294 while (attributesCount-- > 0) { 1295 // Read the attribute_info's attribute_name and attribute_length fields. 1296 String attributeName = readUTF8(currentOffset, charBuffer); 1297 int attributeLength = readInt(currentOffset + 2); 1298 currentOffset += 6; 1299 // The tests are sorted in decreasing frequency order (based on frequencies observed on 1300 // typical classes). 1301 if (Constants.CODE.equals(attributeName)) { 1302 if ((context.parsingOptions & SKIP_CODE) == 0) { 1303 codeOffset = currentOffset; 1304 } 1305 } else if (Constants.EXCEPTIONS.equals(attributeName)) { 1306 exceptionsOffset = currentOffset; 1307 exceptions = new String[readUnsignedShort(exceptionsOffset)]; 1308 int currentExceptionOffset = exceptionsOffset + 2; 1309 for (int i = 0; i < exceptions.length; ++i) { 1310 exceptions[i] = readClass(currentExceptionOffset, charBuffer); 1311 currentExceptionOffset += 2; 1312 } 1313 } else if (Constants.SIGNATURE.equals(attributeName)) { 1314 signatureIndex = readUnsignedShort(currentOffset); 1315 } else if (Constants.DEPRECATED.equals(attributeName)) { 1316 context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED; 1317 } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { 1318 runtimeVisibleAnnotationsOffset = currentOffset; 1319 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 1320 runtimeVisibleTypeAnnotationsOffset = currentOffset; 1321 } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) { 1322 annotationDefaultOffset = currentOffset; 1323 } else if (Constants.SYNTHETIC.equals(attributeName)) { 1324 synthetic = true; 1325 context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC; 1326 } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { 1327 runtimeInvisibleAnnotationsOffset = currentOffset; 1328 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 1329 runtimeInvisibleTypeAnnotationsOffset = currentOffset; 1330 } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { 1331 runtimeVisibleParameterAnnotationsOffset = currentOffset; 1332 } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { 1333 runtimeInvisibleParameterAnnotationsOffset = currentOffset; 1334 } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) { 1335 methodParametersOffset = currentOffset; 1336 } else { 1337 Attribute attribute = 1338 readAttribute( 1339 context.attributePrototypes, 1340 attributeName, 1341 currentOffset, 1342 attributeLength, 1343 charBuffer, 1344 -1, 1345 null); 1346 attribute.nextAttribute = attributes; 1347 attributes = attribute; 1348 } 1349 currentOffset += attributeLength; 1350 } 1351 1352 // Visit the method declaration. 1353 MethodVisitor methodVisitor = 1354 classVisitor.visitMethod( 1355 context.currentMethodAccessFlags, 1356 context.currentMethodName, 1357 context.currentMethodDescriptor, 1358 signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer), 1359 exceptions); 1360 if (methodVisitor == null) { 1361 return currentOffset; 1362 } 1363 1364 // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method 1365 // adapter between the reader and the writer. In this case, it might be possible to copy 1366 // the method attributes directly into the writer. If so, return early without visiting 1367 // the content of these attributes. 1368 if (methodVisitor instanceof MethodWriter) { 1369 MethodWriter methodWriter = (MethodWriter) methodVisitor; 1370 if (methodWriter.canCopyMethodAttributes( 1371 this, 1372 synthetic, 1373 (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0, 1374 readUnsignedShort(methodInfoOffset + 4), 1375 signatureIndex, 1376 exceptionsOffset)) { 1377 methodWriter.setMethodAttributesSource(methodInfoOffset, currentOffset - methodInfoOffset); 1378 return currentOffset; 1379 } 1380 } 1381 1382 // Visit the MethodParameters attribute. 1383 if (methodParametersOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { 1384 int parametersCount = readByte(methodParametersOffset); 1385 int currentParameterOffset = methodParametersOffset + 1; 1386 while (parametersCount-- > 0) { 1387 // Read the name_index and access_flags fields and visit them. 1388 methodVisitor.visitParameter( 1389 readUTF8(currentParameterOffset, charBuffer), 1390 readUnsignedShort(currentParameterOffset + 2)); 1391 currentParameterOffset += 4; 1392 } 1393 } 1394 1395 // Visit the AnnotationDefault attribute. 1396 if (annotationDefaultOffset != 0) { 1397 AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault(); 1398 readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer); 1399 if (annotationVisitor != null) { 1400 annotationVisitor.visitEnd(); 1401 } 1402 } 1403 1404 // Visit the RuntimeVisibleAnnotations attribute. 1405 if (runtimeVisibleAnnotationsOffset != 0) { 1406 int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); 1407 int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; 1408 while (numAnnotations-- > 0) { 1409 // Parse the type_index field. 1410 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1411 currentAnnotationOffset += 2; 1412 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1413 currentAnnotationOffset = 1414 readElementValues( 1415 methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), 1416 currentAnnotationOffset, 1417 /* named = */ true, 1418 charBuffer); 1419 } 1420 } 1421 1422 // Visit the RuntimeInvisibleAnnotations attribute. 1423 if (runtimeInvisibleAnnotationsOffset != 0) { 1424 int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); 1425 int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; 1426 while (numAnnotations-- > 0) { 1427 // Parse the type_index field. 1428 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1429 currentAnnotationOffset += 2; 1430 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1431 currentAnnotationOffset = 1432 readElementValues( 1433 methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), 1434 currentAnnotationOffset, 1435 /* named = */ true, 1436 charBuffer); 1437 } 1438 } 1439 1440 // Visit the RuntimeVisibleTypeAnnotations attribute. 1441 if (runtimeVisibleTypeAnnotationsOffset != 0) { 1442 int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); 1443 int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; 1444 while (numAnnotations-- > 0) { 1445 // Parse the target_type, target_info and target_path fields. 1446 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 1447 // Parse the type_index field. 1448 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1449 currentAnnotationOffset += 2; 1450 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1451 currentAnnotationOffset = 1452 readElementValues( 1453 methodVisitor.visitTypeAnnotation( 1454 context.currentTypeAnnotationTarget, 1455 context.currentTypeAnnotationTargetPath, 1456 annotationDescriptor, 1457 /* visible = */ true), 1458 currentAnnotationOffset, 1459 /* named = */ true, 1460 charBuffer); 1461 } 1462 } 1463 1464 // Visit the RuntimeInvisibleTypeAnnotations attribute. 1465 if (runtimeInvisibleTypeAnnotationsOffset != 0) { 1466 int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); 1467 int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; 1468 while (numAnnotations-- > 0) { 1469 // Parse the target_type, target_info and target_path fields. 1470 currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); 1471 // Parse the type_index field. 1472 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 1473 currentAnnotationOffset += 2; 1474 // Parse num_element_value_pairs and element_value_pairs and visit these values. 1475 currentAnnotationOffset = 1476 readElementValues( 1477 methodVisitor.visitTypeAnnotation( 1478 context.currentTypeAnnotationTarget, 1479 context.currentTypeAnnotationTargetPath, 1480 annotationDescriptor, 1481 /* visible = */ false), 1482 currentAnnotationOffset, 1483 /* named = */ true, 1484 charBuffer); 1485 } 1486 } 1487 1488 // Visit the RuntimeVisibleParameterAnnotations attribute. 1489 if (runtimeVisibleParameterAnnotationsOffset != 0) { 1490 readParameterAnnotations( 1491 methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true); 1492 } 1493 1494 // Visit the RuntimeInvisibleParameterAnnotations attribute. 1495 if (runtimeInvisibleParameterAnnotationsOffset != 0) { 1496 readParameterAnnotations( 1497 methodVisitor, 1498 context, 1499 runtimeInvisibleParameterAnnotationsOffset, 1500 /* visible = */ false); 1501 } 1502 1503 // Visit the non standard attributes. 1504 while (attributes != null) { 1505 // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. 1506 Attribute nextAttribute = attributes.nextAttribute; 1507 attributes.nextAttribute = null; 1508 methodVisitor.visitAttribute(attributes); 1509 attributes = nextAttribute; 1510 } 1511 1512 // Visit the Code attribute. 1513 if (codeOffset != 0) { 1514 methodVisitor.visitCode(); 1515 readCode(methodVisitor, context, codeOffset); 1516 } 1517 1518 // Visit the end of the method. 1519 methodVisitor.visitEnd(); 1520 return currentOffset; 1521 } 1522 1523 // ---------------------------------------------------------------------------------------------- 1524 // Methods to parse a Code attribute 1525 // ---------------------------------------------------------------------------------------------- 1526 1527 /** 1528 * Reads a JVMS 'Code' attribute and makes the given visitor visit it. 1529 * 1530 * @param methodVisitor the visitor that must visit the Code attribute. 1531 * @param context information about the class being parsed. 1532 * @param codeOffset the start offset in {@link #classFileBuffer} of the Code attribute, excluding 1533 * its attribute_name_index and attribute_length fields. 1534 */ readCode( final MethodVisitor methodVisitor, final Context context, final int codeOffset)1535 private void readCode( 1536 final MethodVisitor methodVisitor, final Context context, final int codeOffset) { 1537 int currentOffset = codeOffset; 1538 1539 // Read the max_stack, max_locals and code_length fields. 1540 final byte[] classBuffer = classFileBuffer; 1541 final char[] charBuffer = context.charBuffer; 1542 final int maxStack = readUnsignedShort(currentOffset); 1543 final int maxLocals = readUnsignedShort(currentOffset + 2); 1544 final int codeLength = readInt(currentOffset + 4); 1545 currentOffset += 8; 1546 if (codeLength > classFileBuffer.length - currentOffset) { 1547 throw new IllegalArgumentException(); 1548 } 1549 1550 // Read the bytecode 'code' array to create a label for each referenced instruction. 1551 final int bytecodeStartOffset = currentOffset; 1552 final int bytecodeEndOffset = currentOffset + codeLength; 1553 final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1]; 1554 while (currentOffset < bytecodeEndOffset) { 1555 final int bytecodeOffset = currentOffset - bytecodeStartOffset; 1556 final int opcode = classBuffer[currentOffset] & 0xFF; 1557 switch (opcode) { 1558 case Opcodes.NOP: 1559 case Opcodes.ACONST_NULL: 1560 case Opcodes.ICONST_M1: 1561 case Opcodes.ICONST_0: 1562 case Opcodes.ICONST_1: 1563 case Opcodes.ICONST_2: 1564 case Opcodes.ICONST_3: 1565 case Opcodes.ICONST_4: 1566 case Opcodes.ICONST_5: 1567 case Opcodes.LCONST_0: 1568 case Opcodes.LCONST_1: 1569 case Opcodes.FCONST_0: 1570 case Opcodes.FCONST_1: 1571 case Opcodes.FCONST_2: 1572 case Opcodes.DCONST_0: 1573 case Opcodes.DCONST_1: 1574 case Opcodes.IALOAD: 1575 case Opcodes.LALOAD: 1576 case Opcodes.FALOAD: 1577 case Opcodes.DALOAD: 1578 case Opcodes.AALOAD: 1579 case Opcodes.BALOAD: 1580 case Opcodes.CALOAD: 1581 case Opcodes.SALOAD: 1582 case Opcodes.IASTORE: 1583 case Opcodes.LASTORE: 1584 case Opcodes.FASTORE: 1585 case Opcodes.DASTORE: 1586 case Opcodes.AASTORE: 1587 case Opcodes.BASTORE: 1588 case Opcodes.CASTORE: 1589 case Opcodes.SASTORE: 1590 case Opcodes.POP: 1591 case Opcodes.POP2: 1592 case Opcodes.DUP: 1593 case Opcodes.DUP_X1: 1594 case Opcodes.DUP_X2: 1595 case Opcodes.DUP2: 1596 case Opcodes.DUP2_X1: 1597 case Opcodes.DUP2_X2: 1598 case Opcodes.SWAP: 1599 case Opcodes.IADD: 1600 case Opcodes.LADD: 1601 case Opcodes.FADD: 1602 case Opcodes.DADD: 1603 case Opcodes.ISUB: 1604 case Opcodes.LSUB: 1605 case Opcodes.FSUB: 1606 case Opcodes.DSUB: 1607 case Opcodes.IMUL: 1608 case Opcodes.LMUL: 1609 case Opcodes.FMUL: 1610 case Opcodes.DMUL: 1611 case Opcodes.IDIV: 1612 case Opcodes.LDIV: 1613 case Opcodes.FDIV: 1614 case Opcodes.DDIV: 1615 case Opcodes.IREM: 1616 case Opcodes.LREM: 1617 case Opcodes.FREM: 1618 case Opcodes.DREM: 1619 case Opcodes.INEG: 1620 case Opcodes.LNEG: 1621 case Opcodes.FNEG: 1622 case Opcodes.DNEG: 1623 case Opcodes.ISHL: 1624 case Opcodes.LSHL: 1625 case Opcodes.ISHR: 1626 case Opcodes.LSHR: 1627 case Opcodes.IUSHR: 1628 case Opcodes.LUSHR: 1629 case Opcodes.IAND: 1630 case Opcodes.LAND: 1631 case Opcodes.IOR: 1632 case Opcodes.LOR: 1633 case Opcodes.IXOR: 1634 case Opcodes.LXOR: 1635 case Opcodes.I2L: 1636 case Opcodes.I2F: 1637 case Opcodes.I2D: 1638 case Opcodes.L2I: 1639 case Opcodes.L2F: 1640 case Opcodes.L2D: 1641 case Opcodes.F2I: 1642 case Opcodes.F2L: 1643 case Opcodes.F2D: 1644 case Opcodes.D2I: 1645 case Opcodes.D2L: 1646 case Opcodes.D2F: 1647 case Opcodes.I2B: 1648 case Opcodes.I2C: 1649 case Opcodes.I2S: 1650 case Opcodes.LCMP: 1651 case Opcodes.FCMPL: 1652 case Opcodes.FCMPG: 1653 case Opcodes.DCMPL: 1654 case Opcodes.DCMPG: 1655 case Opcodes.IRETURN: 1656 case Opcodes.LRETURN: 1657 case Opcodes.FRETURN: 1658 case Opcodes.DRETURN: 1659 case Opcodes.ARETURN: 1660 case Opcodes.RETURN: 1661 case Opcodes.ARRAYLENGTH: 1662 case Opcodes.ATHROW: 1663 case Opcodes.MONITORENTER: 1664 case Opcodes.MONITOREXIT: 1665 case Constants.ILOAD_0: 1666 case Constants.ILOAD_1: 1667 case Constants.ILOAD_2: 1668 case Constants.ILOAD_3: 1669 case Constants.LLOAD_0: 1670 case Constants.LLOAD_1: 1671 case Constants.LLOAD_2: 1672 case Constants.LLOAD_3: 1673 case Constants.FLOAD_0: 1674 case Constants.FLOAD_1: 1675 case Constants.FLOAD_2: 1676 case Constants.FLOAD_3: 1677 case Constants.DLOAD_0: 1678 case Constants.DLOAD_1: 1679 case Constants.DLOAD_2: 1680 case Constants.DLOAD_3: 1681 case Constants.ALOAD_0: 1682 case Constants.ALOAD_1: 1683 case Constants.ALOAD_2: 1684 case Constants.ALOAD_3: 1685 case Constants.ISTORE_0: 1686 case Constants.ISTORE_1: 1687 case Constants.ISTORE_2: 1688 case Constants.ISTORE_3: 1689 case Constants.LSTORE_0: 1690 case Constants.LSTORE_1: 1691 case Constants.LSTORE_2: 1692 case Constants.LSTORE_3: 1693 case Constants.FSTORE_0: 1694 case Constants.FSTORE_1: 1695 case Constants.FSTORE_2: 1696 case Constants.FSTORE_3: 1697 case Constants.DSTORE_0: 1698 case Constants.DSTORE_1: 1699 case Constants.DSTORE_2: 1700 case Constants.DSTORE_3: 1701 case Constants.ASTORE_0: 1702 case Constants.ASTORE_1: 1703 case Constants.ASTORE_2: 1704 case Constants.ASTORE_3: 1705 currentOffset += 1; 1706 break; 1707 case Opcodes.IFEQ: 1708 case Opcodes.IFNE: 1709 case Opcodes.IFLT: 1710 case Opcodes.IFGE: 1711 case Opcodes.IFGT: 1712 case Opcodes.IFLE: 1713 case Opcodes.IF_ICMPEQ: 1714 case Opcodes.IF_ICMPNE: 1715 case Opcodes.IF_ICMPLT: 1716 case Opcodes.IF_ICMPGE: 1717 case Opcodes.IF_ICMPGT: 1718 case Opcodes.IF_ICMPLE: 1719 case Opcodes.IF_ACMPEQ: 1720 case Opcodes.IF_ACMPNE: 1721 case Opcodes.GOTO: 1722 case Opcodes.JSR: 1723 case Opcodes.IFNULL: 1724 case Opcodes.IFNONNULL: 1725 createLabel(bytecodeOffset + readShort(currentOffset + 1), labels); 1726 currentOffset += 3; 1727 break; 1728 case Constants.ASM_IFEQ: 1729 case Constants.ASM_IFNE: 1730 case Constants.ASM_IFLT: 1731 case Constants.ASM_IFGE: 1732 case Constants.ASM_IFGT: 1733 case Constants.ASM_IFLE: 1734 case Constants.ASM_IF_ICMPEQ: 1735 case Constants.ASM_IF_ICMPNE: 1736 case Constants.ASM_IF_ICMPLT: 1737 case Constants.ASM_IF_ICMPGE: 1738 case Constants.ASM_IF_ICMPGT: 1739 case Constants.ASM_IF_ICMPLE: 1740 case Constants.ASM_IF_ACMPEQ: 1741 case Constants.ASM_IF_ACMPNE: 1742 case Constants.ASM_GOTO: 1743 case Constants.ASM_JSR: 1744 case Constants.ASM_IFNULL: 1745 case Constants.ASM_IFNONNULL: 1746 createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels); 1747 currentOffset += 3; 1748 break; 1749 case Constants.GOTO_W: 1750 case Constants.JSR_W: 1751 case Constants.ASM_GOTO_W: 1752 createLabel(bytecodeOffset + readInt(currentOffset + 1), labels); 1753 currentOffset += 5; 1754 break; 1755 case Constants.WIDE: 1756 switch (classBuffer[currentOffset + 1] & 0xFF) { 1757 case Opcodes.ILOAD: 1758 case Opcodes.FLOAD: 1759 case Opcodes.ALOAD: 1760 case Opcodes.LLOAD: 1761 case Opcodes.DLOAD: 1762 case Opcodes.ISTORE: 1763 case Opcodes.FSTORE: 1764 case Opcodes.ASTORE: 1765 case Opcodes.LSTORE: 1766 case Opcodes.DSTORE: 1767 case Opcodes.RET: 1768 currentOffset += 4; 1769 break; 1770 case Opcodes.IINC: 1771 currentOffset += 6; 1772 break; 1773 default: 1774 throw new IllegalArgumentException(); 1775 } 1776 break; 1777 case Opcodes.TABLESWITCH: 1778 // Skip 0 to 3 padding bytes. 1779 currentOffset += 4 - (bytecodeOffset & 3); 1780 // Read the default label and the number of table entries. 1781 createLabel(bytecodeOffset + readInt(currentOffset), labels); 1782 int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1; 1783 currentOffset += 12; 1784 // Read the table labels. 1785 while (numTableEntries-- > 0) { 1786 createLabel(bytecodeOffset + readInt(currentOffset), labels); 1787 currentOffset += 4; 1788 } 1789 break; 1790 case Opcodes.LOOKUPSWITCH: 1791 // Skip 0 to 3 padding bytes. 1792 currentOffset += 4 - (bytecodeOffset & 3); 1793 // Read the default label and the number of switch cases. 1794 createLabel(bytecodeOffset + readInt(currentOffset), labels); 1795 int numSwitchCases = readInt(currentOffset + 4); 1796 currentOffset += 8; 1797 // Read the switch labels. 1798 while (numSwitchCases-- > 0) { 1799 createLabel(bytecodeOffset + readInt(currentOffset + 4), labels); 1800 currentOffset += 8; 1801 } 1802 break; 1803 case Opcodes.ILOAD: 1804 case Opcodes.LLOAD: 1805 case Opcodes.FLOAD: 1806 case Opcodes.DLOAD: 1807 case Opcodes.ALOAD: 1808 case Opcodes.ISTORE: 1809 case Opcodes.LSTORE: 1810 case Opcodes.FSTORE: 1811 case Opcodes.DSTORE: 1812 case Opcodes.ASTORE: 1813 case Opcodes.RET: 1814 case Opcodes.BIPUSH: 1815 case Opcodes.NEWARRAY: 1816 case Opcodes.LDC: 1817 currentOffset += 2; 1818 break; 1819 case Opcodes.SIPUSH: 1820 case Constants.LDC_W: 1821 case Constants.LDC2_W: 1822 case Opcodes.GETSTATIC: 1823 case Opcodes.PUTSTATIC: 1824 case Opcodes.GETFIELD: 1825 case Opcodes.PUTFIELD: 1826 case Opcodes.INVOKEVIRTUAL: 1827 case Opcodes.INVOKESPECIAL: 1828 case Opcodes.INVOKESTATIC: 1829 case Opcodes.NEW: 1830 case Opcodes.ANEWARRAY: 1831 case Opcodes.CHECKCAST: 1832 case Opcodes.INSTANCEOF: 1833 case Opcodes.IINC: 1834 currentOffset += 3; 1835 break; 1836 case Opcodes.INVOKEINTERFACE: 1837 case Opcodes.INVOKEDYNAMIC: 1838 currentOffset += 5; 1839 break; 1840 case Opcodes.MULTIANEWARRAY: 1841 currentOffset += 4; 1842 break; 1843 default: 1844 throw new IllegalArgumentException(); 1845 } 1846 } 1847 1848 // Read the 'exception_table_length' and 'exception_table' field to create a label for each 1849 // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks. 1850 int exceptionTableLength = readUnsignedShort(currentOffset); 1851 currentOffset += 2; 1852 while (exceptionTableLength-- > 0) { 1853 Label start = createLabel(readUnsignedShort(currentOffset), labels); 1854 Label end = createLabel(readUnsignedShort(currentOffset + 2), labels); 1855 Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels); 1856 String catchType = readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer); 1857 currentOffset += 8; 1858 methodVisitor.visitTryCatchBlock(start, end, handler, catchType); 1859 } 1860 1861 // Read the Code attributes to create a label for each referenced instruction (the variables 1862 // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the 1863 // attribute_name_index and attribute_length fields. 1864 // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0. 1865 // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is 1866 // updated after each stack_map_frame is read. 1867 int stackMapFrameOffset = 0; 1868 // - The end offset of the StackMap[Table] attribute, or 0. 1869 int stackMapTableEndOffset = 0; 1870 // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not. 1871 boolean compressedFrames = true; 1872 // - The offset of the LocalVariableTable attribute, or 0. 1873 int localVariableTableOffset = 0; 1874 // - The offset of the LocalVariableTypeTable attribute, or 0. 1875 int localVariableTypeTableOffset = 0; 1876 // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations 1877 // attribute, or null. 1878 int[] visibleTypeAnnotationOffsets = null; 1879 // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations 1880 // attribute, or null. 1881 int[] invisibleTypeAnnotationOffsets = null; 1882 // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). 1883 // This list in the <i>reverse order</i> or their order in the ClassFile structure. 1884 Attribute attributes = null; 1885 1886 int attributesCount = readUnsignedShort(currentOffset); 1887 currentOffset += 2; 1888 while (attributesCount-- > 0) { 1889 // Read the attribute_info's attribute_name and attribute_length fields. 1890 String attributeName = readUTF8(currentOffset, charBuffer); 1891 int attributeLength = readInt(currentOffset + 2); 1892 currentOffset += 6; 1893 if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) { 1894 if ((context.parsingOptions & SKIP_DEBUG) == 0) { 1895 localVariableTableOffset = currentOffset; 1896 // Parse the attribute to find the corresponding (debug only) labels. 1897 int currentLocalVariableTableOffset = currentOffset; 1898 int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset); 1899 currentLocalVariableTableOffset += 2; 1900 while (localVariableTableLength-- > 0) { 1901 int startPc = readUnsignedShort(currentLocalVariableTableOffset); 1902 createDebugLabel(startPc, labels); 1903 int length = readUnsignedShort(currentLocalVariableTableOffset + 2); 1904 createDebugLabel(startPc + length, labels); 1905 // Skip the name_index, descriptor_index and index fields (2 bytes each). 1906 currentLocalVariableTableOffset += 10; 1907 } 1908 } 1909 } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) { 1910 localVariableTypeTableOffset = currentOffset; 1911 // Here we do not extract the labels corresponding to the attribute content. We assume they 1912 // are the same or a subset of those of the LocalVariableTable attribute. 1913 } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) { 1914 if ((context.parsingOptions & SKIP_DEBUG) == 0) { 1915 // Parse the attribute to find the corresponding (debug only) labels. 1916 int currentLineNumberTableOffset = currentOffset; 1917 int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset); 1918 currentLineNumberTableOffset += 2; 1919 while (lineNumberTableLength-- > 0) { 1920 int startPc = readUnsignedShort(currentLineNumberTableOffset); 1921 int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2); 1922 currentLineNumberTableOffset += 4; 1923 createDebugLabel(startPc, labels); 1924 labels[startPc].addLineNumber(lineNumber); 1925 } 1926 } 1927 } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 1928 visibleTypeAnnotationOffsets = 1929 readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true); 1930 // Here we do not extract the labels corresponding to the attribute content. This would 1931 // require a full parsing of the attribute, which would need to be repeated when parsing 1932 // the bytecode instructions (see below). Instead, the content of the attribute is read one 1933 // type annotation at a time (i.e. after a type annotation has been visited, the next type 1934 // annotation is read), and the labels it contains are also extracted one annotation at a 1935 // time. This assumes that type annotations are ordered by increasing bytecode offset. 1936 } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { 1937 invisibleTypeAnnotationOffsets = 1938 readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false); 1939 // Same comment as above for the RuntimeVisibleTypeAnnotations attribute. 1940 } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) { 1941 if ((context.parsingOptions & SKIP_FRAMES) == 0) { 1942 stackMapFrameOffset = currentOffset + 2; 1943 stackMapTableEndOffset = currentOffset + attributeLength; 1944 } 1945 // Here we do not extract the labels corresponding to the attribute content. This would 1946 // require a full parsing of the attribute, which would need to be repeated when parsing 1947 // the bytecode instructions (see below). Instead, the content of the attribute is read one 1948 // frame at a time (i.e. after a frame has been visited, the next frame is read), and the 1949 // labels it contains are also extracted one frame at a time. Thanks to the ordering of 1950 // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to 1951 // see an offset smaller than the offset of the current instruction and for which no Label 1952 // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map 1953 // table without a full decoding (see below). 1954 } else if ("StackMap".equals(attributeName)) { 1955 if ((context.parsingOptions & SKIP_FRAMES) == 0) { 1956 stackMapFrameOffset = currentOffset + 2; 1957 stackMapTableEndOffset = currentOffset + attributeLength; 1958 compressedFrames = false; 1959 } 1960 // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute, 1961 // although this is not guaranteed by the attribute format. This allows an incremental 1962 // extraction of the labels corresponding to this attribute (see the comment above for the 1963 // StackMapTable attribute). 1964 } else { 1965 Attribute attribute = 1966 readAttribute( 1967 context.attributePrototypes, 1968 attributeName, 1969 currentOffset, 1970 attributeLength, 1971 charBuffer, 1972 codeOffset, 1973 labels); 1974 attribute.nextAttribute = attributes; 1975 attributes = attribute; 1976 } 1977 currentOffset += attributeLength; 1978 } 1979 1980 // Initialize the context fields related to stack map frames, and generate the first 1981 // (implicit) stack map frame, if needed. 1982 final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0; 1983 if (stackMapFrameOffset != 0) { 1984 // The bytecode offset of the first explicit frame is not offset_delta + 1 but only 1985 // offset_delta. Setting the implicit frame offset to -1 allows us to use of the 1986 // "offset_delta + 1" rule in all cases. 1987 context.currentFrameOffset = -1; 1988 context.currentFrameType = 0; 1989 context.currentFrameLocalCount = 0; 1990 context.currentFrameLocalCountDelta = 0; 1991 context.currentFrameLocalTypes = new Object[maxLocals]; 1992 context.currentFrameStackCount = 0; 1993 context.currentFrameStackTypes = new Object[maxStack]; 1994 if (expandFrames) { 1995 computeImplicitFrame(context); 1996 } 1997 // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the 1998 // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type 1999 // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset). 2000 // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare, 2001 // and the only consequence will be the creation of an unneeded label. This is better than 2002 // creating a label for each NEW instruction, and faster than fully decoding the whole stack 2003 // map table. 2004 for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) { 2005 if (classBuffer[offset] == Frame.ITEM_UNINITIALIZED) { 2006 int potentialBytecodeOffset = readUnsignedShort(offset + 1); 2007 if (potentialBytecodeOffset >= 0 2008 && potentialBytecodeOffset < codeLength 2009 && (classBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF) 2010 == Opcodes.NEW) { 2011 createLabel(potentialBytecodeOffset, labels); 2012 } 2013 } 2014 } 2015 } 2016 if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) { 2017 // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method 2018 // does not currently have any frame. These inserted frames must be computed by simulating the 2019 // effect of the bytecode instructions, one by one, starting from the implicit first frame. 2020 // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To 2021 // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is 2022 // computed in MethodWriter). 2023 methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null); 2024 } 2025 2026 // Visit the bytecode instructions. First, introduce state variables for the incremental parsing 2027 // of the type annotations. 2028 2029 // Index of the next runtime visible type annotation to read (in the 2030 // visibleTypeAnnotationOffsets array). 2031 int currentVisibleTypeAnnotationIndex = 0; 2032 // The bytecode offset of the next runtime visible type annotation to read, or -1. 2033 int currentVisibleTypeAnnotationBytecodeOffset = 2034 getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0); 2035 // Index of the next runtime invisible type annotation to read (in the 2036 // invisibleTypeAnnotationOffsets array). 2037 int currentInvisibleTypeAnnotationIndex = 0; 2038 // The bytecode offset of the next runtime invisible type annotation to read, or -1. 2039 int currentInvisibleTypeAnnotationBytecodeOffset = 2040 getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0); 2041 2042 // Whether a F_INSERT stack map frame must be inserted before the current instruction. 2043 boolean insertFrame = false; 2044 2045 // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr 2046 // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific 2047 // instructions). 2048 final int wideJumpOpcodeDelta = 2049 (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0; 2050 2051 currentOffset = bytecodeStartOffset; 2052 while (currentOffset < bytecodeEndOffset) { 2053 final int currentBytecodeOffset = currentOffset - bytecodeStartOffset; 2054 readBytecodeInstructionOffset(currentBytecodeOffset); 2055 2056 // Visit the label and the line number(s) for this bytecode offset, if any. 2057 Label currentLabel = labels[currentBytecodeOffset]; 2058 if (currentLabel != null) { 2059 currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0); 2060 } 2061 2062 // Visit the stack map frame for this bytecode offset, if any. 2063 while (stackMapFrameOffset != 0 2064 && (context.currentFrameOffset == currentBytecodeOffset 2065 || context.currentFrameOffset == -1)) { 2066 // If there is a stack map frame for this offset, make methodVisitor visit it, and read the 2067 // next stack map frame if there is one. 2068 if (context.currentFrameOffset != -1) { 2069 if (!compressedFrames || expandFrames) { 2070 methodVisitor.visitFrame( 2071 Opcodes.F_NEW, 2072 context.currentFrameLocalCount, 2073 context.currentFrameLocalTypes, 2074 context.currentFrameStackCount, 2075 context.currentFrameStackTypes); 2076 } else { 2077 methodVisitor.visitFrame( 2078 context.currentFrameType, 2079 context.currentFrameLocalCountDelta, 2080 context.currentFrameLocalTypes, 2081 context.currentFrameStackCount, 2082 context.currentFrameStackTypes); 2083 } 2084 // Since there is already a stack map frame for this bytecode offset, there is no need to 2085 // insert a new one. 2086 insertFrame = false; 2087 } 2088 if (stackMapFrameOffset < stackMapTableEndOffset) { 2089 stackMapFrameOffset = 2090 readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context); 2091 } else { 2092 stackMapFrameOffset = 0; 2093 } 2094 } 2095 2096 // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to 2097 // true during the previous iteration. The actual frame content is computed in MethodWriter. 2098 if (insertFrame) { 2099 if ((context.parsingOptions & EXPAND_FRAMES) != 0) { 2100 methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null); 2101 } 2102 insertFrame = false; 2103 } 2104 2105 // Visit the instruction at this bytecode offset. 2106 int opcode = classBuffer[currentOffset] & 0xFF; 2107 switch (opcode) { 2108 case Opcodes.NOP: 2109 case Opcodes.ACONST_NULL: 2110 case Opcodes.ICONST_M1: 2111 case Opcodes.ICONST_0: 2112 case Opcodes.ICONST_1: 2113 case Opcodes.ICONST_2: 2114 case Opcodes.ICONST_3: 2115 case Opcodes.ICONST_4: 2116 case Opcodes.ICONST_5: 2117 case Opcodes.LCONST_0: 2118 case Opcodes.LCONST_1: 2119 case Opcodes.FCONST_0: 2120 case Opcodes.FCONST_1: 2121 case Opcodes.FCONST_2: 2122 case Opcodes.DCONST_0: 2123 case Opcodes.DCONST_1: 2124 case Opcodes.IALOAD: 2125 case Opcodes.LALOAD: 2126 case Opcodes.FALOAD: 2127 case Opcodes.DALOAD: 2128 case Opcodes.AALOAD: 2129 case Opcodes.BALOAD: 2130 case Opcodes.CALOAD: 2131 case Opcodes.SALOAD: 2132 case Opcodes.IASTORE: 2133 case Opcodes.LASTORE: 2134 case Opcodes.FASTORE: 2135 case Opcodes.DASTORE: 2136 case Opcodes.AASTORE: 2137 case Opcodes.BASTORE: 2138 case Opcodes.CASTORE: 2139 case Opcodes.SASTORE: 2140 case Opcodes.POP: 2141 case Opcodes.POP2: 2142 case Opcodes.DUP: 2143 case Opcodes.DUP_X1: 2144 case Opcodes.DUP_X2: 2145 case Opcodes.DUP2: 2146 case Opcodes.DUP2_X1: 2147 case Opcodes.DUP2_X2: 2148 case Opcodes.SWAP: 2149 case Opcodes.IADD: 2150 case Opcodes.LADD: 2151 case Opcodes.FADD: 2152 case Opcodes.DADD: 2153 case Opcodes.ISUB: 2154 case Opcodes.LSUB: 2155 case Opcodes.FSUB: 2156 case Opcodes.DSUB: 2157 case Opcodes.IMUL: 2158 case Opcodes.LMUL: 2159 case Opcodes.FMUL: 2160 case Opcodes.DMUL: 2161 case Opcodes.IDIV: 2162 case Opcodes.LDIV: 2163 case Opcodes.FDIV: 2164 case Opcodes.DDIV: 2165 case Opcodes.IREM: 2166 case Opcodes.LREM: 2167 case Opcodes.FREM: 2168 case Opcodes.DREM: 2169 case Opcodes.INEG: 2170 case Opcodes.LNEG: 2171 case Opcodes.FNEG: 2172 case Opcodes.DNEG: 2173 case Opcodes.ISHL: 2174 case Opcodes.LSHL: 2175 case Opcodes.ISHR: 2176 case Opcodes.LSHR: 2177 case Opcodes.IUSHR: 2178 case Opcodes.LUSHR: 2179 case Opcodes.IAND: 2180 case Opcodes.LAND: 2181 case Opcodes.IOR: 2182 case Opcodes.LOR: 2183 case Opcodes.IXOR: 2184 case Opcodes.LXOR: 2185 case Opcodes.I2L: 2186 case Opcodes.I2F: 2187 case Opcodes.I2D: 2188 case Opcodes.L2I: 2189 case Opcodes.L2F: 2190 case Opcodes.L2D: 2191 case Opcodes.F2I: 2192 case Opcodes.F2L: 2193 case Opcodes.F2D: 2194 case Opcodes.D2I: 2195 case Opcodes.D2L: 2196 case Opcodes.D2F: 2197 case Opcodes.I2B: 2198 case Opcodes.I2C: 2199 case Opcodes.I2S: 2200 case Opcodes.LCMP: 2201 case Opcodes.FCMPL: 2202 case Opcodes.FCMPG: 2203 case Opcodes.DCMPL: 2204 case Opcodes.DCMPG: 2205 case Opcodes.IRETURN: 2206 case Opcodes.LRETURN: 2207 case Opcodes.FRETURN: 2208 case Opcodes.DRETURN: 2209 case Opcodes.ARETURN: 2210 case Opcodes.RETURN: 2211 case Opcodes.ARRAYLENGTH: 2212 case Opcodes.ATHROW: 2213 case Opcodes.MONITORENTER: 2214 case Opcodes.MONITOREXIT: 2215 methodVisitor.visitInsn(opcode); 2216 currentOffset += 1; 2217 break; 2218 case Constants.ILOAD_0: 2219 case Constants.ILOAD_1: 2220 case Constants.ILOAD_2: 2221 case Constants.ILOAD_3: 2222 case Constants.LLOAD_0: 2223 case Constants.LLOAD_1: 2224 case Constants.LLOAD_2: 2225 case Constants.LLOAD_3: 2226 case Constants.FLOAD_0: 2227 case Constants.FLOAD_1: 2228 case Constants.FLOAD_2: 2229 case Constants.FLOAD_3: 2230 case Constants.DLOAD_0: 2231 case Constants.DLOAD_1: 2232 case Constants.DLOAD_2: 2233 case Constants.DLOAD_3: 2234 case Constants.ALOAD_0: 2235 case Constants.ALOAD_1: 2236 case Constants.ALOAD_2: 2237 case Constants.ALOAD_3: 2238 opcode -= Constants.ILOAD_0; 2239 methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); 2240 currentOffset += 1; 2241 break; 2242 case Constants.ISTORE_0: 2243 case Constants.ISTORE_1: 2244 case Constants.ISTORE_2: 2245 case Constants.ISTORE_3: 2246 case Constants.LSTORE_0: 2247 case Constants.LSTORE_1: 2248 case Constants.LSTORE_2: 2249 case Constants.LSTORE_3: 2250 case Constants.FSTORE_0: 2251 case Constants.FSTORE_1: 2252 case Constants.FSTORE_2: 2253 case Constants.FSTORE_3: 2254 case Constants.DSTORE_0: 2255 case Constants.DSTORE_1: 2256 case Constants.DSTORE_2: 2257 case Constants.DSTORE_3: 2258 case Constants.ASTORE_0: 2259 case Constants.ASTORE_1: 2260 case Constants.ASTORE_2: 2261 case Constants.ASTORE_3: 2262 opcode -= Constants.ISTORE_0; 2263 methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); 2264 currentOffset += 1; 2265 break; 2266 case Opcodes.IFEQ: 2267 case Opcodes.IFNE: 2268 case Opcodes.IFLT: 2269 case Opcodes.IFGE: 2270 case Opcodes.IFGT: 2271 case Opcodes.IFLE: 2272 case Opcodes.IF_ICMPEQ: 2273 case Opcodes.IF_ICMPNE: 2274 case Opcodes.IF_ICMPLT: 2275 case Opcodes.IF_ICMPGE: 2276 case Opcodes.IF_ICMPGT: 2277 case Opcodes.IF_ICMPLE: 2278 case Opcodes.IF_ACMPEQ: 2279 case Opcodes.IF_ACMPNE: 2280 case Opcodes.GOTO: 2281 case Opcodes.JSR: 2282 case Opcodes.IFNULL: 2283 case Opcodes.IFNONNULL: 2284 methodVisitor.visitJumpInsn( 2285 opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]); 2286 currentOffset += 3; 2287 break; 2288 case Constants.GOTO_W: 2289 case Constants.JSR_W: 2290 methodVisitor.visitJumpInsn( 2291 opcode - wideJumpOpcodeDelta, 2292 labels[currentBytecodeOffset + readInt(currentOffset + 1)]); 2293 currentOffset += 5; 2294 break; 2295 case Constants.ASM_IFEQ: 2296 case Constants.ASM_IFNE: 2297 case Constants.ASM_IFLT: 2298 case Constants.ASM_IFGE: 2299 case Constants.ASM_IFGT: 2300 case Constants.ASM_IFLE: 2301 case Constants.ASM_IF_ICMPEQ: 2302 case Constants.ASM_IF_ICMPNE: 2303 case Constants.ASM_IF_ICMPLT: 2304 case Constants.ASM_IF_ICMPGE: 2305 case Constants.ASM_IF_ICMPGT: 2306 case Constants.ASM_IF_ICMPLE: 2307 case Constants.ASM_IF_ACMPEQ: 2308 case Constants.ASM_IF_ACMPNE: 2309 case Constants.ASM_GOTO: 2310 case Constants.ASM_JSR: 2311 case Constants.ASM_IFNULL: 2312 case Constants.ASM_IFNONNULL: 2313 { 2314 // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO 2315 // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., 2316 // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and 2317 // where <L> designates the instruction just after the GOTO_W. 2318 // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and 2319 // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. 2320 opcode = 2321 opcode < Constants.ASM_IFNULL 2322 ? opcode - Constants.ASM_OPCODE_DELTA 2323 : opcode - Constants.ASM_IFNULL_OPCODE_DELTA; 2324 Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)]; 2325 if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { 2326 // Replace GOTO with GOTO_W and JSR with JSR_W. 2327 methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target); 2328 } else { 2329 // Compute the "opposite" of opcode. This can be done by flipping the least 2330 // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ 2331 // (with a pre and post offset by 1). 2332 opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1; 2333 Label endif = createLabel(currentBytecodeOffset + 3, labels); 2334 methodVisitor.visitJumpInsn(opcode, endif); 2335 methodVisitor.visitJumpInsn(Constants.GOTO_W, target); 2336 // endif designates the instruction just after GOTO_W, and is visited as part of the 2337 // next instruction. Since it is a jump target, we need to insert a frame here. 2338 insertFrame = true; 2339 } 2340 currentOffset += 3; 2341 break; 2342 } 2343 case Constants.ASM_GOTO_W: 2344 // Replace ASM_GOTO_W with GOTO_W. 2345 methodVisitor.visitJumpInsn( 2346 Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]); 2347 // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns 2348 // IFNOTxxx <L> ASM_GOTO_W <l> L:..., see MethodWriter), so we need to insert a frame 2349 // here. 2350 insertFrame = true; 2351 currentOffset += 5; 2352 break; 2353 case Constants.WIDE: 2354 opcode = classBuffer[currentOffset + 1] & 0xFF; 2355 if (opcode == Opcodes.IINC) { 2356 methodVisitor.visitIincInsn( 2357 readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4)); 2358 currentOffset += 6; 2359 } else { 2360 methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2)); 2361 currentOffset += 4; 2362 } 2363 break; 2364 case Opcodes.TABLESWITCH: 2365 { 2366 // Skip 0 to 3 padding bytes. 2367 currentOffset += 4 - (currentBytecodeOffset & 3); 2368 // Read the instruction. 2369 Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; 2370 int low = readInt(currentOffset + 4); 2371 int high = readInt(currentOffset + 8); 2372 currentOffset += 12; 2373 Label[] table = new Label[high - low + 1]; 2374 for (int i = 0; i < table.length; ++i) { 2375 table[i] = labels[currentBytecodeOffset + readInt(currentOffset)]; 2376 currentOffset += 4; 2377 } 2378 methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table); 2379 break; 2380 } 2381 case Opcodes.LOOKUPSWITCH: 2382 { 2383 // Skip 0 to 3 padding bytes. 2384 currentOffset += 4 - (currentBytecodeOffset & 3); 2385 // Read the instruction. 2386 Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; 2387 int numPairs = readInt(currentOffset + 4); 2388 currentOffset += 8; 2389 int[] keys = new int[numPairs]; 2390 Label[] values = new Label[numPairs]; 2391 for (int i = 0; i < numPairs; ++i) { 2392 keys[i] = readInt(currentOffset); 2393 values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; 2394 currentOffset += 8; 2395 } 2396 methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values); 2397 break; 2398 } 2399 case Opcodes.ILOAD: 2400 case Opcodes.LLOAD: 2401 case Opcodes.FLOAD: 2402 case Opcodes.DLOAD: 2403 case Opcodes.ALOAD: 2404 case Opcodes.ISTORE: 2405 case Opcodes.LSTORE: 2406 case Opcodes.FSTORE: 2407 case Opcodes.DSTORE: 2408 case Opcodes.ASTORE: 2409 case Opcodes.RET: 2410 methodVisitor.visitVarInsn(opcode, classBuffer[currentOffset + 1] & 0xFF); 2411 currentOffset += 2; 2412 break; 2413 case Opcodes.BIPUSH: 2414 case Opcodes.NEWARRAY: 2415 methodVisitor.visitIntInsn(opcode, classBuffer[currentOffset + 1]); 2416 currentOffset += 2; 2417 break; 2418 case Opcodes.SIPUSH: 2419 methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1)); 2420 currentOffset += 3; 2421 break; 2422 case Opcodes.LDC: 2423 methodVisitor.visitLdcInsn(readConst(classBuffer[currentOffset + 1] & 0xFF, charBuffer)); 2424 currentOffset += 2; 2425 break; 2426 case Constants.LDC_W: 2427 case Constants.LDC2_W: 2428 methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer)); 2429 currentOffset += 3; 2430 break; 2431 case Opcodes.GETSTATIC: 2432 case Opcodes.PUTSTATIC: 2433 case Opcodes.GETFIELD: 2434 case Opcodes.PUTFIELD: 2435 case Opcodes.INVOKEVIRTUAL: 2436 case Opcodes.INVOKESPECIAL: 2437 case Opcodes.INVOKESTATIC: 2438 case Opcodes.INVOKEINTERFACE: 2439 { 2440 int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; 2441 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; 2442 String owner = readClass(cpInfoOffset, charBuffer); 2443 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 2444 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 2445 if (opcode < Opcodes.INVOKEVIRTUAL) { 2446 methodVisitor.visitFieldInsn(opcode, owner, name, descriptor); 2447 } else { 2448 boolean isInterface = 2449 classBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; 2450 methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); 2451 } 2452 if (opcode == Opcodes.INVOKEINTERFACE) { 2453 currentOffset += 5; 2454 } else { 2455 currentOffset += 3; 2456 } 2457 break; 2458 } 2459 case Opcodes.INVOKEDYNAMIC: 2460 { 2461 int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; 2462 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; 2463 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 2464 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 2465 int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; 2466 Handle handle = 2467 (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 2468 Object[] bootstrapMethodArguments = 2469 new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; 2470 bootstrapMethodOffset += 4; 2471 for (int i = 0; i < bootstrapMethodArguments.length; i++) { 2472 bootstrapMethodArguments[i] = 2473 readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 2474 bootstrapMethodOffset += 2; 2475 } 2476 methodVisitor.visitInvokeDynamicInsn( 2477 name, descriptor, handle, bootstrapMethodArguments); 2478 currentOffset += 5; 2479 break; 2480 } 2481 case Opcodes.NEW: 2482 case Opcodes.ANEWARRAY: 2483 case Opcodes.CHECKCAST: 2484 case Opcodes.INSTANCEOF: 2485 methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer)); 2486 currentOffset += 3; 2487 break; 2488 case Opcodes.IINC: 2489 methodVisitor.visitIincInsn( 2490 classBuffer[currentOffset + 1] & 0xFF, classBuffer[currentOffset + 2]); 2491 currentOffset += 3; 2492 break; 2493 case Opcodes.MULTIANEWARRAY: 2494 methodVisitor.visitMultiANewArrayInsn( 2495 readClass(currentOffset + 1, charBuffer), classBuffer[currentOffset + 3] & 0xFF); 2496 currentOffset += 4; 2497 break; 2498 default: 2499 throw new AssertionError(); 2500 } 2501 2502 // Visit the runtime visible instruction annotations, if any. 2503 while (visibleTypeAnnotationOffsets != null 2504 && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length 2505 && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { 2506 if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { 2507 // Parse the target_type, target_info and target_path fields. 2508 int currentAnnotationOffset = 2509 readTypeAnnotationTarget( 2510 context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]); 2511 // Parse the type_index field. 2512 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 2513 currentAnnotationOffset += 2; 2514 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2515 readElementValues( 2516 methodVisitor.visitInsnAnnotation( 2517 context.currentTypeAnnotationTarget, 2518 context.currentTypeAnnotationTargetPath, 2519 annotationDescriptor, 2520 /* visible = */ true), 2521 currentAnnotationOffset, 2522 /* named = */ true, 2523 charBuffer); 2524 } 2525 currentVisibleTypeAnnotationBytecodeOffset = 2526 getTypeAnnotationBytecodeOffset( 2527 visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex); 2528 } 2529 2530 // Visit the runtime invisible instruction annotations, if any. 2531 while (invisibleTypeAnnotationOffsets != null 2532 && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length 2533 && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { 2534 if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { 2535 // Parse the target_type, target_info and target_path fields. 2536 int currentAnnotationOffset = 2537 readTypeAnnotationTarget( 2538 context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]); 2539 // Parse the type_index field. 2540 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 2541 currentAnnotationOffset += 2; 2542 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2543 readElementValues( 2544 methodVisitor.visitInsnAnnotation( 2545 context.currentTypeAnnotationTarget, 2546 context.currentTypeAnnotationTargetPath, 2547 annotationDescriptor, 2548 /* visible = */ false), 2549 currentAnnotationOffset, 2550 /* named = */ true, 2551 charBuffer); 2552 } 2553 currentInvisibleTypeAnnotationBytecodeOffset = 2554 getTypeAnnotationBytecodeOffset( 2555 invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex); 2556 } 2557 } 2558 if (labels[codeLength] != null) { 2559 methodVisitor.visitLabel(labels[codeLength]); 2560 } 2561 2562 // Visit LocalVariableTable and LocalVariableTypeTable attributes. 2563 if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { 2564 // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable. 2565 int[] typeTable = null; 2566 if (localVariableTypeTableOffset != 0) { 2567 typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3]; 2568 currentOffset = localVariableTypeTableOffset + 2; 2569 int typeTableIndex = typeTable.length; 2570 while (typeTableIndex > 0) { 2571 // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'. 2572 typeTable[--typeTableIndex] = currentOffset + 6; 2573 typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8); 2574 typeTable[--typeTableIndex] = readUnsignedShort(currentOffset); 2575 currentOffset += 10; 2576 } 2577 } 2578 int localVariableTableLength = readUnsignedShort(localVariableTableOffset); 2579 currentOffset = localVariableTableOffset + 2; 2580 while (localVariableTableLength-- > 0) { 2581 int startPc = readUnsignedShort(currentOffset); 2582 int length = readUnsignedShort(currentOffset + 2); 2583 String name = readUTF8(currentOffset + 4, charBuffer); 2584 String descriptor = readUTF8(currentOffset + 6, charBuffer); 2585 int index = readUnsignedShort(currentOffset + 8); 2586 currentOffset += 10; 2587 String signature = null; 2588 if (typeTable != null) { 2589 for (int i = 0; i < typeTable.length; i += 3) { 2590 if (typeTable[i] == startPc && typeTable[i + 1] == index) { 2591 signature = readUTF8(typeTable[i + 2], charBuffer); 2592 break; 2593 } 2594 } 2595 } 2596 methodVisitor.visitLocalVariable( 2597 name, descriptor, signature, labels[startPc], labels[startPc + length], index); 2598 } 2599 } 2600 2601 // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute. 2602 if (visibleTypeAnnotationOffsets != null) { 2603 for (int typeAnnotationOffset : visibleTypeAnnotationOffsets) { 2604 int targetType = readByte(typeAnnotationOffset); 2605 if (targetType == TypeReference.LOCAL_VARIABLE 2606 || targetType == TypeReference.RESOURCE_VARIABLE) { 2607 // Parse the target_type, target_info and target_path fields. 2608 currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); 2609 // Parse the type_index field. 2610 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2611 currentOffset += 2; 2612 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2613 readElementValues( 2614 methodVisitor.visitLocalVariableAnnotation( 2615 context.currentTypeAnnotationTarget, 2616 context.currentTypeAnnotationTargetPath, 2617 context.currentLocalVariableAnnotationRangeStarts, 2618 context.currentLocalVariableAnnotationRangeEnds, 2619 context.currentLocalVariableAnnotationRangeIndices, 2620 annotationDescriptor, 2621 /* visible = */ true), 2622 currentOffset, 2623 /* named = */ true, 2624 charBuffer); 2625 } 2626 } 2627 } 2628 2629 // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute. 2630 if (invisibleTypeAnnotationOffsets != null) { 2631 for (int typeAnnotationOffset : invisibleTypeAnnotationOffsets) { 2632 int targetType = readByte(typeAnnotationOffset); 2633 if (targetType == TypeReference.LOCAL_VARIABLE 2634 || targetType == TypeReference.RESOURCE_VARIABLE) { 2635 // Parse the target_type, target_info and target_path fields. 2636 currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); 2637 // Parse the type_index field. 2638 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2639 currentOffset += 2; 2640 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2641 readElementValues( 2642 methodVisitor.visitLocalVariableAnnotation( 2643 context.currentTypeAnnotationTarget, 2644 context.currentTypeAnnotationTargetPath, 2645 context.currentLocalVariableAnnotationRangeStarts, 2646 context.currentLocalVariableAnnotationRangeEnds, 2647 context.currentLocalVariableAnnotationRangeIndices, 2648 annotationDescriptor, 2649 /* visible = */ false), 2650 currentOffset, 2651 /* named = */ true, 2652 charBuffer); 2653 } 2654 } 2655 } 2656 2657 // Visit the non standard attributes. 2658 while (attributes != null) { 2659 // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. 2660 Attribute nextAttribute = attributes.nextAttribute; 2661 attributes.nextAttribute = null; 2662 methodVisitor.visitAttribute(attributes); 2663 attributes = nextAttribute; 2664 } 2665 2666 // Visit the max stack and max locals values. 2667 methodVisitor.visitMaxs(maxStack, maxLocals); 2668 } 2669 2670 /** 2671 * Handles the bytecode offset of the next instruction to be visited in {@link 2672 * #accept(ClassVisitor,int)}. This method is called just before the instruction and before its 2673 * associated label and stack map frame, if any. The default implementation of this method does 2674 * nothing. Subclasses can override this method to store the argument in a mutable field, for 2675 * instance, so that {@link MethodVisitor} instances can get the bytecode offset of each visited 2676 * instruction (if so, the usual concurrency issues related to mutable data should be addressed). 2677 * 2678 * @param bytecodeOffset the bytecode offset of the next instruction to be visited. 2679 */ 2680 protected void readBytecodeInstructionOffset(final int bytecodeOffset) { 2681 // Do nothing by default. 2682 } 2683 2684 /** 2685 * Returns the label corresponding to the given bytecode offset. The default implementation of 2686 * this method creates a label for the given offset if it has not been already created. 2687 * 2688 * @param bytecodeOffset a bytecode offset in a method. 2689 * @param labels the already created labels, indexed by their offset. If a label already exists 2690 * for bytecodeOffset this method must not create a new one. Otherwise it must store the new 2691 * label in this array. 2692 * @return a non null Label, which must be equal to labels[bytecodeOffset]. 2693 */ 2694 protected Label readLabel(final int bytecodeOffset, final Label[] labels) { 2695 if (labels[bytecodeOffset] == null) { 2696 labels[bytecodeOffset] = new Label(); 2697 } 2698 return labels[bytecodeOffset]; 2699 } 2700 2701 /** 2702 * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode 2703 * offset. The label is created with a call to {@link #readLabel} and its {@link 2704 * Label#FLAG_DEBUG_ONLY} flag is cleared. 2705 * 2706 * @param bytecodeOffset a bytecode offset in a method. 2707 * @param labels the already created labels, indexed by their offset. 2708 * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set. 2709 */ 2710 private Label createLabel(final int bytecodeOffset, final Label[] labels) { 2711 Label label = readLabel(bytecodeOffset, labels); 2712 label.flags &= ~Label.FLAG_DEBUG_ONLY; 2713 return label; 2714 } 2715 2716 /** 2717 * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already 2718 * existing label for the given bytecode offset (otherwise does nothing). The label is created 2719 * with a call to {@link #readLabel}. 2720 * 2721 * @param bytecodeOffset a bytecode offset in a method. 2722 * @param labels the already created labels, indexed by their offset. 2723 */ 2724 private void createDebugLabel(final int bytecodeOffset, final Label[] labels) { 2725 if (labels[bytecodeOffset] == null) { 2726 readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY; 2727 } 2728 } 2729 2730 // ---------------------------------------------------------------------------------------------- 2731 // Methods to parse annotations, type annotations and parameter annotations 2732 // ---------------------------------------------------------------------------------------------- 2733 2734 /** 2735 * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation 2736 * entry it contains, to find the corresponding labels, and to visit the try catch block 2737 * annotations. 2738 * 2739 * @param methodVisitor the method visitor to be used to visit the try catch block annotations. 2740 * @param context information about the class being parsed. 2741 * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations 2742 * attribute, excluding the attribute_info's attribute_name_index and attribute_length fields. 2743 * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute, 2744 * false it is a RuntimeInvisibleTypeAnnotations attribute. 2745 * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's 2746 * 'annotations' array field. 2747 */ 2748 private int[] readTypeAnnotations( 2749 final MethodVisitor methodVisitor, 2750 final Context context, 2751 final int runtimeTypeAnnotationsOffset, 2752 final boolean visible) { 2753 char[] charBuffer = context.charBuffer; 2754 int currentOffset = runtimeTypeAnnotationsOffset; 2755 // Read the num_annotations field and create an array to store the type_annotation offsets. 2756 int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)]; 2757 currentOffset += 2; 2758 // Parse the 'annotations' array field. 2759 for (int i = 0; i < typeAnnotationsOffsets.length; ++i) { 2760 typeAnnotationsOffsets[i] = currentOffset; 2761 // Parse the type_annotation's target_type and the target_info fields. The size of the 2762 // target_info field depends on the value of target_type. 2763 int targetType = readInt(currentOffset); 2764 switch (targetType >>> 24) { 2765 case TypeReference.LOCAL_VARIABLE: 2766 case TypeReference.RESOURCE_VARIABLE: 2767 // A localvar_target has a variable size, which depends on the value of their table_length 2768 // field. It also references bytecode offsets, for which we need labels. 2769 int tableLength = readUnsignedShort(currentOffset + 1); 2770 currentOffset += 3; 2771 while (tableLength-- > 0) { 2772 int startPc = readUnsignedShort(currentOffset); 2773 int length = readUnsignedShort(currentOffset + 2); 2774 // Skip the index field (2 bytes). 2775 currentOffset += 6; 2776 createLabel(startPc, context.currentMethodLabels); 2777 createLabel(startPc + length, context.currentMethodLabels); 2778 } 2779 break; 2780 case TypeReference.CAST: 2781 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 2782 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 2783 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 2784 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 2785 currentOffset += 4; 2786 break; 2787 case TypeReference.CLASS_EXTENDS: 2788 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 2789 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 2790 case TypeReference.THROWS: 2791 case TypeReference.EXCEPTION_PARAMETER: 2792 case TypeReference.INSTANCEOF: 2793 case TypeReference.NEW: 2794 case TypeReference.CONSTRUCTOR_REFERENCE: 2795 case TypeReference.METHOD_REFERENCE: 2796 currentOffset += 3; 2797 break; 2798 case TypeReference.CLASS_TYPE_PARAMETER: 2799 case TypeReference.METHOD_TYPE_PARAMETER: 2800 case TypeReference.METHOD_FORMAL_PARAMETER: 2801 case TypeReference.FIELD: 2802 case TypeReference.METHOD_RETURN: 2803 case TypeReference.METHOD_RECEIVER: 2804 default: 2805 // TypeReference type which can't be used in Code attribute, or which is unknown. 2806 throw new IllegalArgumentException(); 2807 } 2808 // Parse the rest of the type_annotation structure, starting with the target_path structure 2809 // (whose size depends on its path_length field). 2810 int pathLength = readByte(currentOffset); 2811 if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) { 2812 // Parse the target_path structure and create a corresponding TypePath. 2813 TypePath path = pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); 2814 currentOffset += 1 + 2 * pathLength; 2815 // Parse the type_index field. 2816 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2817 currentOffset += 2; 2818 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2819 currentOffset = 2820 readElementValues( 2821 methodVisitor.visitTryCatchAnnotation( 2822 targetType & 0xFFFFFF00, path, annotationDescriptor, visible), 2823 currentOffset, 2824 /* named = */ true, 2825 charBuffer); 2826 } else { 2827 // We don't want to visit the other target_type annotations, so we just skip them (which 2828 // requires some parsing because the element_value_pairs array has a variable size). First, 2829 // skip the target_path structure: 2830 currentOffset += 3 + 2 * pathLength; 2831 // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them 2832 // with a null AnnotationVisitor). 2833 currentOffset = 2834 readElementValues( 2835 /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer); 2836 } 2837 } 2838 return typeAnnotationsOffsets; 2839 } 2840 2841 /** 2842 * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or 2843 * -1 if there is no such type_annotation of if it does not have a bytecode offset. 2844 * 2845 * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a 2846 * Runtime[In]VisibleTypeAnnotations attribute, or {@literal null}. 2847 * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets. 2848 * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1 2849 * if there is no such type_annotation of if it does not have a bytecode offset. 2850 */ 2851 private int getTypeAnnotationBytecodeOffset( 2852 final int[] typeAnnotationOffsets, final int typeAnnotationIndex) { 2853 if (typeAnnotationOffsets == null 2854 || typeAnnotationIndex >= typeAnnotationOffsets.length 2855 || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) { 2856 return -1; 2857 } 2858 return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1); 2859 } 2860 2861 /** 2862 * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info 2863 * and target_path (the result is stored in the given context), and returns the start offset of 2864 * the rest of the type_annotation structure. 2865 * 2866 * @param context information about the class being parsed. This is where the extracted 2867 * target_type and target_path must be stored. 2868 * @param typeAnnotationOffset the start offset of a type_annotation structure. 2869 * @return the start offset of the rest of the type_annotation structure. 2870 */ 2871 private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) { 2872 int currentOffset = typeAnnotationOffset; 2873 // Parse and store the target_type structure. 2874 int targetType = readInt(typeAnnotationOffset); 2875 switch (targetType >>> 24) { 2876 case TypeReference.CLASS_TYPE_PARAMETER: 2877 case TypeReference.METHOD_TYPE_PARAMETER: 2878 case TypeReference.METHOD_FORMAL_PARAMETER: 2879 targetType &= 0xFFFF0000; 2880 currentOffset += 2; 2881 break; 2882 case TypeReference.FIELD: 2883 case TypeReference.METHOD_RETURN: 2884 case TypeReference.METHOD_RECEIVER: 2885 targetType &= 0xFF000000; 2886 currentOffset += 1; 2887 break; 2888 case TypeReference.LOCAL_VARIABLE: 2889 case TypeReference.RESOURCE_VARIABLE: 2890 targetType &= 0xFF000000; 2891 int tableLength = readUnsignedShort(currentOffset + 1); 2892 currentOffset += 3; 2893 context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength]; 2894 context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength]; 2895 context.currentLocalVariableAnnotationRangeIndices = new int[tableLength]; 2896 for (int i = 0; i < tableLength; ++i) { 2897 int startPc = readUnsignedShort(currentOffset); 2898 int length = readUnsignedShort(currentOffset + 2); 2899 int index = readUnsignedShort(currentOffset + 4); 2900 currentOffset += 6; 2901 context.currentLocalVariableAnnotationRangeStarts[i] = 2902 createLabel(startPc, context.currentMethodLabels); 2903 context.currentLocalVariableAnnotationRangeEnds[i] = 2904 createLabel(startPc + length, context.currentMethodLabels); 2905 context.currentLocalVariableAnnotationRangeIndices[i] = index; 2906 } 2907 break; 2908 case TypeReference.CAST: 2909 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 2910 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 2911 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 2912 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 2913 targetType &= 0xFF0000FF; 2914 currentOffset += 4; 2915 break; 2916 case TypeReference.CLASS_EXTENDS: 2917 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 2918 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 2919 case TypeReference.THROWS: 2920 case TypeReference.EXCEPTION_PARAMETER: 2921 targetType &= 0xFFFFFF00; 2922 currentOffset += 3; 2923 break; 2924 case TypeReference.INSTANCEOF: 2925 case TypeReference.NEW: 2926 case TypeReference.CONSTRUCTOR_REFERENCE: 2927 case TypeReference.METHOD_REFERENCE: 2928 targetType &= 0xFF000000; 2929 currentOffset += 3; 2930 break; 2931 default: 2932 throw new IllegalArgumentException(); 2933 } 2934 context.currentTypeAnnotationTarget = targetType; 2935 // Parse and store the target_path structure. 2936 int pathLength = readByte(currentOffset); 2937 context.currentTypeAnnotationTargetPath = 2938 pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); 2939 // Return the start offset of the rest of the type_annotation structure. 2940 return currentOffset + 1 + 2 * pathLength; 2941 } 2942 2943 /** 2944 * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it. 2945 * 2946 * @param methodVisitor the visitor that must visit the parameter annotations. 2947 * @param context information about the class being parsed. 2948 * @param runtimeParameterAnnotationsOffset the start offset of a 2949 * Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's 2950 * attribute_name_index and attribute_length fields. 2951 * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations 2952 * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute. 2953 */ readParameterAnnotations( final MethodVisitor methodVisitor, final Context context, final int runtimeParameterAnnotationsOffset, final boolean visible)2954 private void readParameterAnnotations( 2955 final MethodVisitor methodVisitor, 2956 final Context context, 2957 final int runtimeParameterAnnotationsOffset, 2958 final boolean visible) { 2959 int currentOffset = runtimeParameterAnnotationsOffset; 2960 int numParameters = classFileBuffer[currentOffset++] & 0xFF; 2961 methodVisitor.visitAnnotableParameterCount(numParameters, visible); 2962 char[] charBuffer = context.charBuffer; 2963 for (int i = 0; i < numParameters; ++i) { 2964 int numAnnotations = readUnsignedShort(currentOffset); 2965 currentOffset += 2; 2966 while (numAnnotations-- > 0) { 2967 // Parse the type_index field. 2968 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2969 currentOffset += 2; 2970 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2971 currentOffset = 2972 readElementValues( 2973 methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible), 2974 currentOffset, 2975 /* named = */ true, 2976 charBuffer); 2977 } 2978 } 2979 } 2980 2981 /** 2982 * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit 2983 * them. This method can also be used to read the values of the JVMS 'array_value' field of an 2984 * annotation's 'element_value'. 2985 * 2986 * @param annotationVisitor the visitor that must visit the values. 2987 * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index 2988 * field) or of an 'array_value' structure. 2989 * @param named if the annotation values are named or not. This should be true to parse the values 2990 * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an 2991 * annotation's element_value. 2992 * @param charBuffer the buffer used to read strings in the constant pool. 2993 * @return the end offset of the JVMS 'annotation' or 'array_value' structure. 2994 */ readElementValues( final AnnotationVisitor annotationVisitor, final int annotationOffset, final boolean named, final char[] charBuffer)2995 private int readElementValues( 2996 final AnnotationVisitor annotationVisitor, 2997 final int annotationOffset, 2998 final boolean named, 2999 final char[] charBuffer) { 3000 int currentOffset = annotationOffset; 3001 // Read the num_element_value_pairs field (or num_values field for an array_value). 3002 int numElementValuePairs = readUnsignedShort(currentOffset); 3003 currentOffset += 2; 3004 if (named) { 3005 // Parse the element_value_pairs array. 3006 while (numElementValuePairs-- > 0) { 3007 String elementName = readUTF8(currentOffset, charBuffer); 3008 currentOffset = 3009 readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer); 3010 } 3011 } else { 3012 // Parse the array_value array. 3013 while (numElementValuePairs-- > 0) { 3014 currentOffset = 3015 readElementValue(annotationVisitor, currentOffset, /* elementName= */ null, charBuffer); 3016 } 3017 } 3018 if (annotationVisitor != null) { 3019 annotationVisitor.visitEnd(); 3020 } 3021 return currentOffset; 3022 } 3023 3024 /** 3025 * Reads a JVMS 'element_value' structure and makes the given visitor visit it. 3026 * 3027 * @param annotationVisitor the visitor that must visit the element_value structure. 3028 * @param elementValueOffset the start offset in {@link #classFileBuffer} of the element_value 3029 * structure to be read. 3030 * @param elementName the name of the element_value structure to be read, or {@literal null}. 3031 * @param charBuffer the buffer used to read strings in the constant pool. 3032 * @return the end offset of the JVMS 'element_value' structure. 3033 */ readElementValue( final AnnotationVisitor annotationVisitor, final int elementValueOffset, final String elementName, final char[] charBuffer)3034 private int readElementValue( 3035 final AnnotationVisitor annotationVisitor, 3036 final int elementValueOffset, 3037 final String elementName, 3038 final char[] charBuffer) { 3039 int currentOffset = elementValueOffset; 3040 if (annotationVisitor == null) { 3041 switch (classFileBuffer[currentOffset] & 0xFF) { 3042 case 'e': // enum_const_value 3043 return currentOffset + 5; 3044 case '@': // annotation_value 3045 return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer); 3046 case '[': // array_value 3047 return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer); 3048 default: 3049 return currentOffset + 3; 3050 } 3051 } 3052 switch (classFileBuffer[currentOffset++] & 0xFF) { 3053 case 'B': // const_value_index, CONSTANT_Integer 3054 annotationVisitor.visit( 3055 elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); 3056 currentOffset += 2; 3057 break; 3058 case 'C': // const_value_index, CONSTANT_Integer 3059 annotationVisitor.visit( 3060 elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); 3061 currentOffset += 2; 3062 break; 3063 case 'D': // const_value_index, CONSTANT_Double 3064 case 'F': // const_value_index, CONSTANT_Float 3065 case 'I': // const_value_index, CONSTANT_Integer 3066 case 'J': // const_value_index, CONSTANT_Long 3067 annotationVisitor.visit( 3068 elementName, readConst(readUnsignedShort(currentOffset), charBuffer)); 3069 currentOffset += 2; 3070 break; 3071 case 'S': // const_value_index, CONSTANT_Integer 3072 annotationVisitor.visit( 3073 elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); 3074 currentOffset += 2; 3075 break; 3076 3077 case 'Z': // const_value_index, CONSTANT_Integer 3078 annotationVisitor.visit( 3079 elementName, 3080 readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0 3081 ? Boolean.FALSE 3082 : Boolean.TRUE); 3083 currentOffset += 2; 3084 break; 3085 case 's': // const_value_index, CONSTANT_Utf8 3086 annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer)); 3087 currentOffset += 2; 3088 break; 3089 case 'e': // enum_const_value 3090 annotationVisitor.visitEnum( 3091 elementName, 3092 readUTF8(currentOffset, charBuffer), 3093 readUTF8(currentOffset + 2, charBuffer)); 3094 currentOffset += 4; 3095 break; 3096 case 'c': // class_info 3097 annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer))); 3098 currentOffset += 2; 3099 break; 3100 case '@': // annotation_value 3101 currentOffset = 3102 readElementValues( 3103 annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)), 3104 currentOffset + 2, 3105 true, 3106 charBuffer); 3107 break; 3108 case '[': // array_value 3109 int numValues = readUnsignedShort(currentOffset); 3110 currentOffset += 2; 3111 if (numValues == 0) { 3112 return readElementValues( 3113 annotationVisitor.visitArray(elementName), 3114 currentOffset - 2, 3115 /* named = */ false, 3116 charBuffer); 3117 } 3118 switch (classFileBuffer[currentOffset] & 0xFF) { 3119 case 'B': 3120 byte[] byteValues = new byte[numValues]; 3121 for (int i = 0; i < numValues; i++) { 3122 byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3123 currentOffset += 3; 3124 } 3125 annotationVisitor.visit(elementName, byteValues); 3126 break; 3127 case 'Z': 3128 boolean[] booleanValues = new boolean[numValues]; 3129 for (int i = 0; i < numValues; i++) { 3130 booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0; 3131 currentOffset += 3; 3132 } 3133 annotationVisitor.visit(elementName, booleanValues); 3134 break; 3135 case 'S': 3136 short[] shortValues = new short[numValues]; 3137 for (int i = 0; i < numValues; i++) { 3138 shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3139 currentOffset += 3; 3140 } 3141 annotationVisitor.visit(elementName, shortValues); 3142 break; 3143 case 'C': 3144 char[] charValues = new char[numValues]; 3145 for (int i = 0; i < numValues; i++) { 3146 charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3147 currentOffset += 3; 3148 } 3149 annotationVisitor.visit(elementName, charValues); 3150 break; 3151 case 'I': 3152 int[] intValues = new int[numValues]; 3153 for (int i = 0; i < numValues; i++) { 3154 intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3155 currentOffset += 3; 3156 } 3157 annotationVisitor.visit(elementName, intValues); 3158 break; 3159 case 'J': 3160 long[] longValues = new long[numValues]; 3161 for (int i = 0; i < numValues; i++) { 3162 longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3163 currentOffset += 3; 3164 } 3165 annotationVisitor.visit(elementName, longValues); 3166 break; 3167 case 'F': 3168 float[] floatValues = new float[numValues]; 3169 for (int i = 0; i < numValues; i++) { 3170 floatValues[i] = 3171 Float.intBitsToFloat( 3172 readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); 3173 currentOffset += 3; 3174 } 3175 annotationVisitor.visit(elementName, floatValues); 3176 break; 3177 case 'D': 3178 double[] doubleValues = new double[numValues]; 3179 for (int i = 0; i < numValues; i++) { 3180 doubleValues[i] = 3181 Double.longBitsToDouble( 3182 readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); 3183 currentOffset += 3; 3184 } 3185 annotationVisitor.visit(elementName, doubleValues); 3186 break; 3187 default: 3188 currentOffset = 3189 readElementValues( 3190 annotationVisitor.visitArray(elementName), 3191 currentOffset - 2, 3192 /* named = */ false, 3193 charBuffer); 3194 break; 3195 } 3196 break; 3197 default: 3198 throw new IllegalArgumentException(); 3199 } 3200 return currentOffset; 3201 } 3202 3203 // ---------------------------------------------------------------------------------------------- 3204 // Methods to parse stack map frames 3205 // ---------------------------------------------------------------------------------------------- 3206 3207 /** 3208 * Computes the implicit frame of the method currently being parsed (as defined in the given 3209 * {@link Context}) and stores it in the given context. 3210 * 3211 * @param context information about the class being parsed. 3212 */ computeImplicitFrame(final Context context)3213 private void computeImplicitFrame(final Context context) { 3214 String methodDescriptor = context.currentMethodDescriptor; 3215 Object[] locals = context.currentFrameLocalTypes; 3216 int numLocal = 0; 3217 if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) { 3218 if ("<init>".equals(context.currentMethodName)) { 3219 locals[numLocal++] = Opcodes.UNINITIALIZED_THIS; 3220 } else { 3221 locals[numLocal++] = readClass(header + 2, context.charBuffer); 3222 } 3223 } 3224 // Parse the method descriptor, one argument type descriptor at each iteration. Start by 3225 // skipping the first method descriptor character, which is always '('. 3226 int currentMethodDescritorOffset = 1; 3227 while (true) { 3228 int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset; 3229 switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) { 3230 case 'Z': 3231 case 'C': 3232 case 'B': 3233 case 'S': 3234 case 'I': 3235 locals[numLocal++] = Opcodes.INTEGER; 3236 break; 3237 case 'F': 3238 locals[numLocal++] = Opcodes.FLOAT; 3239 break; 3240 case 'J': 3241 locals[numLocal++] = Opcodes.LONG; 3242 break; 3243 case 'D': 3244 locals[numLocal++] = Opcodes.DOUBLE; 3245 break; 3246 case '[': 3247 while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { 3248 ++currentMethodDescritorOffset; 3249 } 3250 if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') { 3251 ++currentMethodDescritorOffset; 3252 while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { 3253 ++currentMethodDescritorOffset; 3254 } 3255 } 3256 locals[numLocal++] = 3257 methodDescriptor.substring( 3258 currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); 3259 break; 3260 case 'L': 3261 while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { 3262 ++currentMethodDescritorOffset; 3263 } 3264 locals[numLocal++] = 3265 methodDescriptor.substring( 3266 currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); 3267 break; 3268 default: 3269 context.currentFrameLocalCount = numLocal; 3270 return; 3271 } 3272 } 3273 } 3274 3275 /** 3276 * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context} 3277 * object. This method can also be used to read a full_frame structure, excluding its frame_type 3278 * field (this is used to parse the legacy StackMap attributes). 3279 * 3280 * @param stackMapFrameOffset the start offset in {@link #classFileBuffer} of the 3281 * stack_map_frame_value structure to be read, or the start offset of a full_frame structure 3282 * (excluding its frame_type field). 3283 * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame' 3284 * structure without its frame_type field. 3285 * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}. 3286 * @param context where the parsed stack map frame must be stored. 3287 * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure. 3288 */ readStackMapFrame( final int stackMapFrameOffset, final boolean compressed, final boolean expand, final Context context)3289 private int readStackMapFrame( 3290 final int stackMapFrameOffset, 3291 final boolean compressed, 3292 final boolean expand, 3293 final Context context) { 3294 int currentOffset = stackMapFrameOffset; 3295 final char[] charBuffer = context.charBuffer; 3296 final Label[] labels = context.currentMethodLabels; 3297 int frameType; 3298 if (compressed) { 3299 // Read the frame_type field. 3300 frameType = classFileBuffer[currentOffset++] & 0xFF; 3301 } else { 3302 frameType = Frame.FULL_FRAME; 3303 context.currentFrameOffset = -1; 3304 } 3305 int offsetDelta; 3306 context.currentFrameLocalCountDelta = 0; 3307 if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) { 3308 offsetDelta = frameType; 3309 context.currentFrameType = Opcodes.F_SAME; 3310 context.currentFrameStackCount = 0; 3311 } else if (frameType < Frame.RESERVED) { 3312 offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME; 3313 currentOffset = 3314 readVerificationTypeInfo( 3315 currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); 3316 context.currentFrameType = Opcodes.F_SAME1; 3317 context.currentFrameStackCount = 1; 3318 } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 3319 offsetDelta = readUnsignedShort(currentOffset); 3320 currentOffset += 2; 3321 if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 3322 currentOffset = 3323 readVerificationTypeInfo( 3324 currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); 3325 context.currentFrameType = Opcodes.F_SAME1; 3326 context.currentFrameStackCount = 1; 3327 } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) { 3328 context.currentFrameType = Opcodes.F_CHOP; 3329 context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType; 3330 context.currentFrameLocalCount -= context.currentFrameLocalCountDelta; 3331 context.currentFrameStackCount = 0; 3332 } else if (frameType == Frame.SAME_FRAME_EXTENDED) { 3333 context.currentFrameType = Opcodes.F_SAME; 3334 context.currentFrameStackCount = 0; 3335 } else if (frameType < Frame.FULL_FRAME) { 3336 int local = expand ? context.currentFrameLocalCount : 0; 3337 for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) { 3338 currentOffset = 3339 readVerificationTypeInfo( 3340 currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels); 3341 } 3342 context.currentFrameType = Opcodes.F_APPEND; 3343 context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED; 3344 context.currentFrameLocalCount += context.currentFrameLocalCountDelta; 3345 context.currentFrameStackCount = 0; 3346 } else { 3347 final int numberOfLocals = readUnsignedShort(currentOffset); 3348 currentOffset += 2; 3349 context.currentFrameType = Opcodes.F_FULL; 3350 context.currentFrameLocalCountDelta = numberOfLocals; 3351 context.currentFrameLocalCount = numberOfLocals; 3352 for (int local = 0; local < numberOfLocals; ++local) { 3353 currentOffset = 3354 readVerificationTypeInfo( 3355 currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels); 3356 } 3357 final int numberOfStackItems = readUnsignedShort(currentOffset); 3358 currentOffset += 2; 3359 context.currentFrameStackCount = numberOfStackItems; 3360 for (int stack = 0; stack < numberOfStackItems; ++stack) { 3361 currentOffset = 3362 readVerificationTypeInfo( 3363 currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels); 3364 } 3365 } 3366 } else { 3367 throw new IllegalArgumentException(); 3368 } 3369 context.currentFrameOffset += offsetDelta + 1; 3370 createLabel(context.currentFrameOffset, labels); 3371 return currentOffset; 3372 } 3373 3374 /** 3375 * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given 3376 * array. 3377 * 3378 * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to 3379 * read. 3380 * @param frame the array where the parsed type must be stored. 3381 * @param index the index in 'frame' where the parsed type must be stored. 3382 * @param charBuffer the buffer used to read strings in the constant pool. 3383 * @param labels the labels of the method currently being parsed, indexed by their offset. If the 3384 * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is 3385 * stored in this array if it does not already exist. 3386 * @return the end offset of the JVMS 'verification_type_info' structure. 3387 */ readVerificationTypeInfo( final int verificationTypeInfoOffset, final Object[] frame, final int index, final char[] charBuffer, final Label[] labels)3388 private int readVerificationTypeInfo( 3389 final int verificationTypeInfoOffset, 3390 final Object[] frame, 3391 final int index, 3392 final char[] charBuffer, 3393 final Label[] labels) { 3394 int currentOffset = verificationTypeInfoOffset; 3395 int tag = classFileBuffer[currentOffset++] & 0xFF; 3396 switch (tag) { 3397 case Frame.ITEM_TOP: 3398 frame[index] = Opcodes.TOP; 3399 break; 3400 case Frame.ITEM_INTEGER: 3401 frame[index] = Opcodes.INTEGER; 3402 break; 3403 case Frame.ITEM_FLOAT: 3404 frame[index] = Opcodes.FLOAT; 3405 break; 3406 case Frame.ITEM_DOUBLE: 3407 frame[index] = Opcodes.DOUBLE; 3408 break; 3409 case Frame.ITEM_LONG: 3410 frame[index] = Opcodes.LONG; 3411 break; 3412 case Frame.ITEM_NULL: 3413 frame[index] = Opcodes.NULL; 3414 break; 3415 case Frame.ITEM_UNINITIALIZED_THIS: 3416 frame[index] = Opcodes.UNINITIALIZED_THIS; 3417 break; 3418 case Frame.ITEM_OBJECT: 3419 frame[index] = readClass(currentOffset, charBuffer); 3420 currentOffset += 2; 3421 break; 3422 case Frame.ITEM_UNINITIALIZED: 3423 frame[index] = createLabel(readUnsignedShort(currentOffset), labels); 3424 currentOffset += 2; 3425 break; 3426 default: 3427 throw new IllegalArgumentException(); 3428 } 3429 return currentOffset; 3430 } 3431 3432 // ---------------------------------------------------------------------------------------------- 3433 // Methods to parse attributes 3434 // ---------------------------------------------------------------------------------------------- 3435 3436 /** 3437 * Returns the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array 3438 * field entry. 3439 * 3440 * @return the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array 3441 * field entry. 3442 */ getFirstAttributeOffset()3443 final int getFirstAttributeOffset() { 3444 // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes 3445 // each), as well as the interfaces array field (2 bytes per interface). 3446 int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2; 3447 3448 // Read the fields_count field. 3449 int fieldsCount = readUnsignedShort(currentOffset); 3450 currentOffset += 2; 3451 // Skip the 'fields' array field. 3452 while (fieldsCount-- > 0) { 3453 // Invariant: currentOffset is the offset of a field_info structure. 3454 // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the 3455 // attributes_count field. 3456 int attributesCount = readUnsignedShort(currentOffset + 6); 3457 currentOffset += 8; 3458 // Skip the 'attributes' array field. 3459 while (attributesCount-- > 0) { 3460 // Invariant: currentOffset is the offset of an attribute_info structure. 3461 // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip 3462 // this many bytes, plus 6 for the attribute_name_index and attribute_length fields 3463 // (yielding the total size of the attribute_info structure). 3464 currentOffset += 6 + readInt(currentOffset + 2); 3465 } 3466 } 3467 3468 // Skip the methods_count and 'methods' fields, using the same method as above. 3469 int methodsCount = readUnsignedShort(currentOffset); 3470 currentOffset += 2; 3471 while (methodsCount-- > 0) { 3472 int attributesCount = readUnsignedShort(currentOffset + 6); 3473 currentOffset += 8; 3474 while (attributesCount-- > 0) { 3475 currentOffset += 6 + readInt(currentOffset + 2); 3476 } 3477 } 3478 3479 // Skip the ClassFile's attributes_count field. 3480 return currentOffset + 2; 3481 } 3482 3483 /** 3484 * Reads the BootstrapMethods attribute to compute the offset of each bootstrap method. 3485 * 3486 * @param maxStringLength a conservative estimate of the maximum length of the strings contained 3487 * in the constant pool of the class. 3488 * @return the offsets of the bootstrap methods. 3489 */ readBootstrapMethodsAttribute(final int maxStringLength)3490 private int[] readBootstrapMethodsAttribute(final int maxStringLength) { 3491 char[] charBuffer = new char[maxStringLength]; 3492 int currentAttributeOffset = getFirstAttributeOffset(); 3493 for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { 3494 // Read the attribute_info's attribute_name and attribute_length fields. 3495 String attributeName = readUTF8(currentAttributeOffset, charBuffer); 3496 int attributeLength = readInt(currentAttributeOffset + 2); 3497 currentAttributeOffset += 6; 3498 if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { 3499 // Read the num_bootstrap_methods field and create an array of this size. 3500 int[] result = new int[readUnsignedShort(currentAttributeOffset)]; 3501 // Compute and store the offset of each 'bootstrap_methods' array field entry. 3502 int currentBootstrapMethodOffset = currentAttributeOffset + 2; 3503 for (int j = 0; j < result.length; ++j) { 3504 result[j] = currentBootstrapMethodOffset; 3505 // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), 3506 // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). 3507 currentBootstrapMethodOffset += 3508 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; 3509 } 3510 return result; 3511 } 3512 currentAttributeOffset += attributeLength; 3513 } 3514 throw new IllegalArgumentException(); 3515 } 3516 3517 /** 3518 * Reads a non standard JVMS 'attribute' structure in {@link #classFileBuffer}. 3519 * 3520 * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of 3521 * the class. Any attribute whose type is not equal to the type of one the prototypes will not 3522 * be parsed: its byte array value will be passed unchanged to the ClassWriter. 3523 * @param type the type of the attribute. 3524 * @param offset the start offset of the JVMS 'attribute' structure in {@link #classFileBuffer}. 3525 * The 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into 3526 * account here. 3527 * @param length the length of the attribute's content (excluding the 6 attribute header bytes). 3528 * @param charBuffer the buffer to be used to read strings in the constant pool. 3529 * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link 3530 * #classFileBuffer}, or -1 if the attribute to be read is not a code attribute. The 6 3531 * attribute header bytes (attribute_name_index and attribute_length) are not taken into 3532 * account here. 3533 * @param labels the labels of the method's code, or {@literal null} if the attribute to be read 3534 * is not a code attribute. 3535 * @return the attribute that has been read. 3536 */ readAttribute( final Attribute[] attributePrototypes, final String type, final int offset, final int length, final char[] charBuffer, final int codeAttributeOffset, final Label[] labels)3537 private Attribute readAttribute( 3538 final Attribute[] attributePrototypes, 3539 final String type, 3540 final int offset, 3541 final int length, 3542 final char[] charBuffer, 3543 final int codeAttributeOffset, 3544 final Label[] labels) { 3545 for (Attribute attributePrototype : attributePrototypes) { 3546 if (attributePrototype.type.equals(type)) { 3547 return attributePrototype.read( 3548 this, offset, length, charBuffer, codeAttributeOffset, labels); 3549 } 3550 } 3551 return new Attribute(type).read(this, offset, length, null, -1, null); 3552 } 3553 3554 // ----------------------------------------------------------------------------------------------- 3555 // Utility methods: low level parsing 3556 // ----------------------------------------------------------------------------------------------- 3557 3558 /** 3559 * Returns the number of entries in the class's constant pool table. 3560 * 3561 * @return the number of entries in the class's constant pool table. 3562 */ getItemCount()3563 public int getItemCount() { 3564 return cpInfoOffsets.length; 3565 } 3566 3567 /** 3568 * Returns the start offset in this {@link ClassReader} of a JVMS 'cp_info' structure (i.e. a 3569 * constant pool entry), plus one. <i>This method is intended for {@link Attribute} sub classes, 3570 * and is normally not needed by class generators or adapters.</i> 3571 * 3572 * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool 3573 * table. 3574 * @return the start offset in this {@link ClassReader} of the corresponding JVMS 'cp_info' 3575 * structure, plus one. 3576 */ getItem(final int constantPoolEntryIndex)3577 public int getItem(final int constantPoolEntryIndex) { 3578 return cpInfoOffsets[constantPoolEntryIndex]; 3579 } 3580 3581 /** 3582 * Returns a conservative estimate of the maximum length of the strings contained in the class's 3583 * constant pool table. 3584 * 3585 * @return a conservative estimate of the maximum length of the strings contained in the class's 3586 * constant pool table. 3587 */ getMaxStringLength()3588 public int getMaxStringLength() { 3589 return maxStringLength; 3590 } 3591 3592 /** 3593 * Reads a byte value in this {@link ClassReader}. <i>This method is intended for {@link 3594 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3595 * 3596 * @param offset the start offset of the value to be read in this {@link ClassReader}. 3597 * @return the read value. 3598 */ readByte(final int offset)3599 public int readByte(final int offset) { 3600 return classFileBuffer[offset] & 0xFF; 3601 } 3602 3603 /** 3604 * Reads an unsigned short value in this {@link ClassReader}. <i>This method is intended for 3605 * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3606 * 3607 * @param offset the start index of the value to be read in this {@link ClassReader}. 3608 * @return the read value. 3609 */ readUnsignedShort(final int offset)3610 public int readUnsignedShort(final int offset) { 3611 byte[] classBuffer = classFileBuffer; 3612 return ((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF); 3613 } 3614 3615 /** 3616 * Reads a signed short value in this {@link ClassReader}. <i>This method is intended for {@link 3617 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3618 * 3619 * @param offset the start offset of the value to be read in this {@link ClassReader}. 3620 * @return the read value. 3621 */ readShort(final int offset)3622 public short readShort(final int offset) { 3623 byte[] classBuffer = classFileBuffer; 3624 return (short) (((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF)); 3625 } 3626 3627 /** 3628 * Reads a signed int value in this {@link ClassReader}. <i>This method is intended for {@link 3629 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3630 * 3631 * @param offset the start offset of the value to be read in this {@link ClassReader}. 3632 * @return the read value. 3633 */ readInt(final int offset)3634 public int readInt(final int offset) { 3635 byte[] classBuffer = classFileBuffer; 3636 return ((classBuffer[offset] & 0xFF) << 24) 3637 | ((classBuffer[offset + 1] & 0xFF) << 16) 3638 | ((classBuffer[offset + 2] & 0xFF) << 8) 3639 | (classBuffer[offset + 3] & 0xFF); 3640 } 3641 3642 /** 3643 * Reads a signed long value in this {@link ClassReader}. <i>This method is intended for {@link 3644 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3645 * 3646 * @param offset the start offset of the value to be read in this {@link ClassReader}. 3647 * @return the read value. 3648 */ readLong(final int offset)3649 public long readLong(final int offset) { 3650 long l1 = readInt(offset); 3651 long l0 = readInt(offset + 4) & 0xFFFFFFFFL; 3652 return (l1 << 32) | l0; 3653 } 3654 3655 /** 3656 * Reads a CONSTANT_Utf8 constant pool entry in this {@link ClassReader}. <i>This method is 3657 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3658 * adapters.</i> 3659 * 3660 * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose 3661 * value is the index of a CONSTANT_Utf8 entry in the class's constant pool table. 3662 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3663 * large. It is not automatically resized. 3664 * @return the String corresponding to the specified CONSTANT_Utf8 entry. 3665 */ 3666 // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). readUTF8(final int offset, final char[] charBuffer)3667 public String readUTF8(final int offset, final char[] charBuffer) { 3668 int constantPoolEntryIndex = readUnsignedShort(offset); 3669 if (offset == 0 || constantPoolEntryIndex == 0) { 3670 return null; 3671 } 3672 return readUtf(constantPoolEntryIndex, charBuffer); 3673 } 3674 3675 /** 3676 * Reads a CONSTANT_Utf8 constant pool entry in {@link #classFileBuffer}. 3677 * 3678 * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool 3679 * table. 3680 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3681 * large. It is not automatically resized. 3682 * @return the String corresponding to the specified CONSTANT_Utf8 entry. 3683 */ readUtf(final int constantPoolEntryIndex, final char[] charBuffer)3684 final String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) { 3685 String value = constantUtf8Values[constantPoolEntryIndex]; 3686 if (value != null) { 3687 return value; 3688 } 3689 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; 3690 return constantUtf8Values[constantPoolEntryIndex] = 3691 readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); 3692 } 3693 3694 /** 3695 * Reads an UTF8 string in {@link #classFileBuffer}. 3696 * 3697 * @param utfOffset the start offset of the UTF8 string to be read. 3698 * @param utfLength the length of the UTF8 string to be read. 3699 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3700 * large. It is not automatically resized. 3701 * @return the String corresponding to the specified UTF8 string. 3702 */ readUtf(final int utfOffset, final int utfLength, final char[] charBuffer)3703 private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) { 3704 int currentOffset = utfOffset; 3705 int endOffset = currentOffset + utfLength; 3706 int strLength = 0; 3707 byte[] classBuffer = classFileBuffer; 3708 while (currentOffset < endOffset) { 3709 int currentByte = classBuffer[currentOffset++]; 3710 if ((currentByte & 0x80) == 0) { 3711 charBuffer[strLength++] = (char) (currentByte & 0x7F); 3712 } else if ((currentByte & 0xE0) == 0xC0) { 3713 charBuffer[strLength++] = 3714 (char) (((currentByte & 0x1F) << 6) + (classBuffer[currentOffset++] & 0x3F)); 3715 } else { 3716 charBuffer[strLength++] = 3717 (char) 3718 (((currentByte & 0xF) << 12) 3719 + ((classBuffer[currentOffset++] & 0x3F) << 6) 3720 + (classBuffer[currentOffset++] & 0x3F)); 3721 } 3722 } 3723 return new String(charBuffer, 0, strLength); 3724 } 3725 3726 /** 3727 * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or 3728 * CONSTANT_Package constant pool entry in {@link #classFileBuffer}. <i>This method is intended 3729 * for {@link Attribute} sub classes, and is normally not needed by class generators or 3730 * adapters.</i> 3731 * 3732 * @param offset the start offset of an unsigned short value in {@link #classFileBuffer}, whose 3733 * value is the index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, 3734 * CONSTANT_Module or CONSTANT_Package entry in class's constant pool table. 3735 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently 3736 * large. It is not automatically resized. 3737 * @return the String corresponding to the specified constant pool entry. 3738 */ readStringish(final int offset, final char[] charBuffer)3739 private String readStringish(final int offset, final char[] charBuffer) { 3740 // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry 3741 // designated by the first two bytes of this cp_info. 3742 return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); 3743 } 3744 3745 /** 3746 * Reads a CONSTANT_Class constant pool entry in this {@link ClassReader}. <i>This method is 3747 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3748 * adapters.</i> 3749 * 3750 * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose 3751 * value is the index of a CONSTANT_Class entry in class's constant pool table. 3752 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently 3753 * large. It is not automatically resized. 3754 * @return the String corresponding to the specified CONSTANT_Class entry. 3755 */ readClass(final int offset, final char[] charBuffer)3756 public String readClass(final int offset, final char[] charBuffer) { 3757 return readStringish(offset, charBuffer); 3758 } 3759 3760 /** 3761 * Reads a CONSTANT_Module constant pool entry in this {@link ClassReader}. <i>This method is 3762 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3763 * adapters.</i> 3764 * 3765 * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose 3766 * value is the index of a CONSTANT_Module entry in class's constant pool table. 3767 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently 3768 * large. It is not automatically resized. 3769 * @return the String corresponding to the specified CONSTANT_Module entry. 3770 */ readModule(final int offset, final char[] charBuffer)3771 public String readModule(final int offset, final char[] charBuffer) { 3772 return readStringish(offset, charBuffer); 3773 } 3774 3775 /** 3776 * Reads a CONSTANT_Package constant pool entry in this {@link ClassReader}. <i>This method is 3777 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3778 * adapters.</i> 3779 * 3780 * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose 3781 * value is the index of a CONSTANT_Package entry in class's constant pool table. 3782 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently 3783 * large. It is not automatically resized. 3784 * @return the String corresponding to the specified CONSTANT_Package entry. 3785 */ readPackage(final int offset, final char[] charBuffer)3786 public String readPackage(final int offset, final char[] charBuffer) { 3787 return readStringish(offset, charBuffer); 3788 } 3789 3790 /** 3791 * Reads a CONSTANT_Dynamic constant pool entry in {@link #classFileBuffer}. 3792 * 3793 * @param constantPoolEntryIndex the index of a CONSTANT_Dynamic entry in the class's constant 3794 * pool table. 3795 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3796 * large. It is not automatically resized. 3797 * @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry. 3798 */ readConstantDynamic( final int constantPoolEntryIndex, final char[] charBuffer)3799 private ConstantDynamic readConstantDynamic( 3800 final int constantPoolEntryIndex, final char[] charBuffer) { 3801 ConstantDynamic constantDynamic = constantDynamicValues[constantPoolEntryIndex]; 3802 if (constantDynamic != null) { 3803 return constantDynamic; 3804 } 3805 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; 3806 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; 3807 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 3808 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 3809 int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; 3810 Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 3811 Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; 3812 bootstrapMethodOffset += 4; 3813 for (int i = 0; i < bootstrapMethodArguments.length; i++) { 3814 bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 3815 bootstrapMethodOffset += 2; 3816 } 3817 return constantDynamicValues[constantPoolEntryIndex] = 3818 new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments); 3819 } 3820 3821 /** 3822 * Reads a numeric or string constant pool entry in this {@link ClassReader}. <i>This method is 3823 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3824 * adapters.</i> 3825 * 3826 * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, 3827 * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, 3828 * CONSTANT_MethodHandle or CONSTANT_Dynamic entry in the class's constant pool. 3829 * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently 3830 * large. It is not automatically resized. 3831 * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, 3832 * {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified 3833 * constant pool entry. 3834 */ readConst(final int constantPoolEntryIndex, final char[] charBuffer)3835 public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) { 3836 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; 3837 switch (classFileBuffer[cpInfoOffset - 1]) { 3838 case Symbol.CONSTANT_INTEGER_TAG: 3839 return readInt(cpInfoOffset); 3840 case Symbol.CONSTANT_FLOAT_TAG: 3841 return Float.intBitsToFloat(readInt(cpInfoOffset)); 3842 case Symbol.CONSTANT_LONG_TAG: 3843 return readLong(cpInfoOffset); 3844 case Symbol.CONSTANT_DOUBLE_TAG: 3845 return Double.longBitsToDouble(readLong(cpInfoOffset)); 3846 case Symbol.CONSTANT_CLASS_TAG: 3847 return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); 3848 case Symbol.CONSTANT_STRING_TAG: 3849 return readUTF8(cpInfoOffset, charBuffer); 3850 case Symbol.CONSTANT_METHOD_TYPE_TAG: 3851 return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); 3852 case Symbol.CONSTANT_METHOD_HANDLE_TAG: 3853 int referenceKind = readByte(cpInfoOffset); 3854 int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; 3855 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; 3856 String owner = readClass(referenceCpInfoOffset, charBuffer); 3857 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 3858 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 3859 boolean isInterface = 3860 classFileBuffer[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; 3861 return new Handle(referenceKind, owner, name, descriptor, isInterface); 3862 case Symbol.CONSTANT_DYNAMIC_TAG: 3863 return readConstantDynamic(constantPoolEntryIndex, charBuffer); 3864 default: 3865 throw new IllegalArgumentException(); 3866 } 3867 } 3868 } 3869