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