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.V21) { 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 readBytecodeInstructionOffset(currentBytecodeOffset); 2054 2055 // Visit the label and the line number(s) for this bytecode offset, if any. 2056 Label currentLabel = labels[currentBytecodeOffset]; 2057 if (currentLabel != null) { 2058 currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0); 2059 } 2060 2061 // Visit the stack map frame for this bytecode offset, if any. 2062 while (stackMapFrameOffset != 0 2063 && (context.currentFrameOffset == currentBytecodeOffset 2064 || context.currentFrameOffset == -1)) { 2065 // If there is a stack map frame for this offset, make methodVisitor visit it, and read the 2066 // next stack map frame if there is one. 2067 if (context.currentFrameOffset != -1) { 2068 if (!compressedFrames || expandFrames) { 2069 methodVisitor.visitFrame( 2070 Opcodes.F_NEW, 2071 context.currentFrameLocalCount, 2072 context.currentFrameLocalTypes, 2073 context.currentFrameStackCount, 2074 context.currentFrameStackTypes); 2075 } else { 2076 methodVisitor.visitFrame( 2077 context.currentFrameType, 2078 context.currentFrameLocalCountDelta, 2079 context.currentFrameLocalTypes, 2080 context.currentFrameStackCount, 2081 context.currentFrameStackTypes); 2082 } 2083 // Since there is already a stack map frame for this bytecode offset, there is no need to 2084 // insert a new one. 2085 insertFrame = false; 2086 } 2087 if (stackMapFrameOffset < stackMapTableEndOffset) { 2088 stackMapFrameOffset = 2089 readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context); 2090 } else { 2091 stackMapFrameOffset = 0; 2092 } 2093 } 2094 2095 // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to 2096 // true during the previous iteration. The actual frame content is computed in MethodWriter. 2097 if (insertFrame) { 2098 if ((context.parsingOptions & EXPAND_FRAMES) != 0) { 2099 methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null); 2100 } 2101 insertFrame = false; 2102 } 2103 2104 // Visit the instruction at this bytecode offset. 2105 int opcode = classBuffer[currentOffset] & 0xFF; 2106 switch (opcode) { 2107 case Opcodes.NOP: 2108 case Opcodes.ACONST_NULL: 2109 case Opcodes.ICONST_M1: 2110 case Opcodes.ICONST_0: 2111 case Opcodes.ICONST_1: 2112 case Opcodes.ICONST_2: 2113 case Opcodes.ICONST_3: 2114 case Opcodes.ICONST_4: 2115 case Opcodes.ICONST_5: 2116 case Opcodes.LCONST_0: 2117 case Opcodes.LCONST_1: 2118 case Opcodes.FCONST_0: 2119 case Opcodes.FCONST_1: 2120 case Opcodes.FCONST_2: 2121 case Opcodes.DCONST_0: 2122 case Opcodes.DCONST_1: 2123 case Opcodes.IALOAD: 2124 case Opcodes.LALOAD: 2125 case Opcodes.FALOAD: 2126 case Opcodes.DALOAD: 2127 case Opcodes.AALOAD: 2128 case Opcodes.BALOAD: 2129 case Opcodes.CALOAD: 2130 case Opcodes.SALOAD: 2131 case Opcodes.IASTORE: 2132 case Opcodes.LASTORE: 2133 case Opcodes.FASTORE: 2134 case Opcodes.DASTORE: 2135 case Opcodes.AASTORE: 2136 case Opcodes.BASTORE: 2137 case Opcodes.CASTORE: 2138 case Opcodes.SASTORE: 2139 case Opcodes.POP: 2140 case Opcodes.POP2: 2141 case Opcodes.DUP: 2142 case Opcodes.DUP_X1: 2143 case Opcodes.DUP_X2: 2144 case Opcodes.DUP2: 2145 case Opcodes.DUP2_X1: 2146 case Opcodes.DUP2_X2: 2147 case Opcodes.SWAP: 2148 case Opcodes.IADD: 2149 case Opcodes.LADD: 2150 case Opcodes.FADD: 2151 case Opcodes.DADD: 2152 case Opcodes.ISUB: 2153 case Opcodes.LSUB: 2154 case Opcodes.FSUB: 2155 case Opcodes.DSUB: 2156 case Opcodes.IMUL: 2157 case Opcodes.LMUL: 2158 case Opcodes.FMUL: 2159 case Opcodes.DMUL: 2160 case Opcodes.IDIV: 2161 case Opcodes.LDIV: 2162 case Opcodes.FDIV: 2163 case Opcodes.DDIV: 2164 case Opcodes.IREM: 2165 case Opcodes.LREM: 2166 case Opcodes.FREM: 2167 case Opcodes.DREM: 2168 case Opcodes.INEG: 2169 case Opcodes.LNEG: 2170 case Opcodes.FNEG: 2171 case Opcodes.DNEG: 2172 case Opcodes.ISHL: 2173 case Opcodes.LSHL: 2174 case Opcodes.ISHR: 2175 case Opcodes.LSHR: 2176 case Opcodes.IUSHR: 2177 case Opcodes.LUSHR: 2178 case Opcodes.IAND: 2179 case Opcodes.LAND: 2180 case Opcodes.IOR: 2181 case Opcodes.LOR: 2182 case Opcodes.IXOR: 2183 case Opcodes.LXOR: 2184 case Opcodes.I2L: 2185 case Opcodes.I2F: 2186 case Opcodes.I2D: 2187 case Opcodes.L2I: 2188 case Opcodes.L2F: 2189 case Opcodes.L2D: 2190 case Opcodes.F2I: 2191 case Opcodes.F2L: 2192 case Opcodes.F2D: 2193 case Opcodes.D2I: 2194 case Opcodes.D2L: 2195 case Opcodes.D2F: 2196 case Opcodes.I2B: 2197 case Opcodes.I2C: 2198 case Opcodes.I2S: 2199 case Opcodes.LCMP: 2200 case Opcodes.FCMPL: 2201 case Opcodes.FCMPG: 2202 case Opcodes.DCMPL: 2203 case Opcodes.DCMPG: 2204 case Opcodes.IRETURN: 2205 case Opcodes.LRETURN: 2206 case Opcodes.FRETURN: 2207 case Opcodes.DRETURN: 2208 case Opcodes.ARETURN: 2209 case Opcodes.RETURN: 2210 case Opcodes.ARRAYLENGTH: 2211 case Opcodes.ATHROW: 2212 case Opcodes.MONITORENTER: 2213 case Opcodes.MONITOREXIT: 2214 methodVisitor.visitInsn(opcode); 2215 currentOffset += 1; 2216 break; 2217 case Constants.ILOAD_0: 2218 case Constants.ILOAD_1: 2219 case Constants.ILOAD_2: 2220 case Constants.ILOAD_3: 2221 case Constants.LLOAD_0: 2222 case Constants.LLOAD_1: 2223 case Constants.LLOAD_2: 2224 case Constants.LLOAD_3: 2225 case Constants.FLOAD_0: 2226 case Constants.FLOAD_1: 2227 case Constants.FLOAD_2: 2228 case Constants.FLOAD_3: 2229 case Constants.DLOAD_0: 2230 case Constants.DLOAD_1: 2231 case Constants.DLOAD_2: 2232 case Constants.DLOAD_3: 2233 case Constants.ALOAD_0: 2234 case Constants.ALOAD_1: 2235 case Constants.ALOAD_2: 2236 case Constants.ALOAD_3: 2237 opcode -= Constants.ILOAD_0; 2238 methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); 2239 currentOffset += 1; 2240 break; 2241 case Constants.ISTORE_0: 2242 case Constants.ISTORE_1: 2243 case Constants.ISTORE_2: 2244 case Constants.ISTORE_3: 2245 case Constants.LSTORE_0: 2246 case Constants.LSTORE_1: 2247 case Constants.LSTORE_2: 2248 case Constants.LSTORE_3: 2249 case Constants.FSTORE_0: 2250 case Constants.FSTORE_1: 2251 case Constants.FSTORE_2: 2252 case Constants.FSTORE_3: 2253 case Constants.DSTORE_0: 2254 case Constants.DSTORE_1: 2255 case Constants.DSTORE_2: 2256 case Constants.DSTORE_3: 2257 case Constants.ASTORE_0: 2258 case Constants.ASTORE_1: 2259 case Constants.ASTORE_2: 2260 case Constants.ASTORE_3: 2261 opcode -= Constants.ISTORE_0; 2262 methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); 2263 currentOffset += 1; 2264 break; 2265 case Opcodes.IFEQ: 2266 case Opcodes.IFNE: 2267 case Opcodes.IFLT: 2268 case Opcodes.IFGE: 2269 case Opcodes.IFGT: 2270 case Opcodes.IFLE: 2271 case Opcodes.IF_ICMPEQ: 2272 case Opcodes.IF_ICMPNE: 2273 case Opcodes.IF_ICMPLT: 2274 case Opcodes.IF_ICMPGE: 2275 case Opcodes.IF_ICMPGT: 2276 case Opcodes.IF_ICMPLE: 2277 case Opcodes.IF_ACMPEQ: 2278 case Opcodes.IF_ACMPNE: 2279 case Opcodes.GOTO: 2280 case Opcodes.JSR: 2281 case Opcodes.IFNULL: 2282 case Opcodes.IFNONNULL: 2283 methodVisitor.visitJumpInsn( 2284 opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]); 2285 currentOffset += 3; 2286 break; 2287 case Constants.GOTO_W: 2288 case Constants.JSR_W: 2289 methodVisitor.visitJumpInsn( 2290 opcode - wideJumpOpcodeDelta, 2291 labels[currentBytecodeOffset + readInt(currentOffset + 1)]); 2292 currentOffset += 5; 2293 break; 2294 case Constants.ASM_IFEQ: 2295 case Constants.ASM_IFNE: 2296 case Constants.ASM_IFLT: 2297 case Constants.ASM_IFGE: 2298 case Constants.ASM_IFGT: 2299 case Constants.ASM_IFLE: 2300 case Constants.ASM_IF_ICMPEQ: 2301 case Constants.ASM_IF_ICMPNE: 2302 case Constants.ASM_IF_ICMPLT: 2303 case Constants.ASM_IF_ICMPGE: 2304 case Constants.ASM_IF_ICMPGT: 2305 case Constants.ASM_IF_ICMPLE: 2306 case Constants.ASM_IF_ACMPEQ: 2307 case Constants.ASM_IF_ACMPNE: 2308 case Constants.ASM_GOTO: 2309 case Constants.ASM_JSR: 2310 case Constants.ASM_IFNULL: 2311 case Constants.ASM_IFNONNULL: 2312 { 2313 // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO 2314 // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx <l> with IFNOTxxx <L> GOTO_W <l> L:..., 2315 // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and 2316 // where <L> designates the instruction just after the GOTO_W. 2317 // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and 2318 // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. 2319 opcode = 2320 opcode < Constants.ASM_IFNULL 2321 ? opcode - Constants.ASM_OPCODE_DELTA 2322 : opcode - Constants.ASM_IFNULL_OPCODE_DELTA; 2323 Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)]; 2324 if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { 2325 // Replace GOTO with GOTO_W and JSR with JSR_W. 2326 methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target); 2327 } else { 2328 // Compute the "opposite" of opcode. This can be done by flipping the least 2329 // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ 2330 // (with a pre and post offset by 1). 2331 opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1; 2332 Label endif = createLabel(currentBytecodeOffset + 3, labels); 2333 methodVisitor.visitJumpInsn(opcode, endif); 2334 methodVisitor.visitJumpInsn(Constants.GOTO_W, target); 2335 // endif designates the instruction just after GOTO_W, and is visited as part of the 2336 // next instruction. Since it is a jump target, we need to insert a frame here. 2337 insertFrame = true; 2338 } 2339 currentOffset += 3; 2340 break; 2341 } 2342 case Constants.ASM_GOTO_W: 2343 // Replace ASM_GOTO_W with GOTO_W. 2344 methodVisitor.visitJumpInsn( 2345 Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]); 2346 // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns 2347 // IFNOTxxx <L> ASM_GOTO_W <l> L:..., see MethodWriter), so we need to insert a frame 2348 // here. 2349 insertFrame = true; 2350 currentOffset += 5; 2351 break; 2352 case Constants.WIDE: 2353 opcode = classBuffer[currentOffset + 1] & 0xFF; 2354 if (opcode == Opcodes.IINC) { 2355 methodVisitor.visitIincInsn( 2356 readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4)); 2357 currentOffset += 6; 2358 } else { 2359 methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2)); 2360 currentOffset += 4; 2361 } 2362 break; 2363 case Opcodes.TABLESWITCH: 2364 { 2365 // Skip 0 to 3 padding bytes. 2366 currentOffset += 4 - (currentBytecodeOffset & 3); 2367 // Read the instruction. 2368 Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; 2369 int low = readInt(currentOffset + 4); 2370 int high = readInt(currentOffset + 8); 2371 currentOffset += 12; 2372 Label[] table = new Label[high - low + 1]; 2373 for (int i = 0; i < table.length; ++i) { 2374 table[i] = labels[currentBytecodeOffset + readInt(currentOffset)]; 2375 currentOffset += 4; 2376 } 2377 methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table); 2378 break; 2379 } 2380 case Opcodes.LOOKUPSWITCH: 2381 { 2382 // Skip 0 to 3 padding bytes. 2383 currentOffset += 4 - (currentBytecodeOffset & 3); 2384 // Read the instruction. 2385 Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; 2386 int numPairs = readInt(currentOffset + 4); 2387 currentOffset += 8; 2388 int[] keys = new int[numPairs]; 2389 Label[] values = new Label[numPairs]; 2390 for (int i = 0; i < numPairs; ++i) { 2391 keys[i] = readInt(currentOffset); 2392 values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; 2393 currentOffset += 8; 2394 } 2395 methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values); 2396 break; 2397 } 2398 case Opcodes.ILOAD: 2399 case Opcodes.LLOAD: 2400 case Opcodes.FLOAD: 2401 case Opcodes.DLOAD: 2402 case Opcodes.ALOAD: 2403 case Opcodes.ISTORE: 2404 case Opcodes.LSTORE: 2405 case Opcodes.FSTORE: 2406 case Opcodes.DSTORE: 2407 case Opcodes.ASTORE: 2408 case Opcodes.RET: 2409 methodVisitor.visitVarInsn(opcode, classBuffer[currentOffset + 1] & 0xFF); 2410 currentOffset += 2; 2411 break; 2412 case Opcodes.BIPUSH: 2413 case Opcodes.NEWARRAY: 2414 methodVisitor.visitIntInsn(opcode, classBuffer[currentOffset + 1]); 2415 currentOffset += 2; 2416 break; 2417 case Opcodes.SIPUSH: 2418 methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1)); 2419 currentOffset += 3; 2420 break; 2421 case Opcodes.LDC: 2422 methodVisitor.visitLdcInsn(readConst(classBuffer[currentOffset + 1] & 0xFF, charBuffer)); 2423 currentOffset += 2; 2424 break; 2425 case Constants.LDC_W: 2426 case Constants.LDC2_W: 2427 methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer)); 2428 currentOffset += 3; 2429 break; 2430 case Opcodes.GETSTATIC: 2431 case Opcodes.PUTSTATIC: 2432 case Opcodes.GETFIELD: 2433 case Opcodes.PUTFIELD: 2434 case Opcodes.INVOKEVIRTUAL: 2435 case Opcodes.INVOKESPECIAL: 2436 case Opcodes.INVOKESTATIC: 2437 case Opcodes.INVOKEINTERFACE: 2438 { 2439 int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; 2440 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; 2441 String owner = readClass(cpInfoOffset, charBuffer); 2442 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 2443 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 2444 if (opcode < Opcodes.INVOKEVIRTUAL) { 2445 methodVisitor.visitFieldInsn(opcode, owner, name, descriptor); 2446 } else { 2447 boolean isInterface = 2448 classBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; 2449 methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); 2450 } 2451 if (opcode == Opcodes.INVOKEINTERFACE) { 2452 currentOffset += 5; 2453 } else { 2454 currentOffset += 3; 2455 } 2456 break; 2457 } 2458 case Opcodes.INVOKEDYNAMIC: 2459 { 2460 int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; 2461 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; 2462 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 2463 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 2464 int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; 2465 Handle handle = 2466 (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 2467 Object[] bootstrapMethodArguments = 2468 new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; 2469 bootstrapMethodOffset += 4; 2470 for (int i = 0; i < bootstrapMethodArguments.length; i++) { 2471 bootstrapMethodArguments[i] = 2472 readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 2473 bootstrapMethodOffset += 2; 2474 } 2475 methodVisitor.visitInvokeDynamicInsn( 2476 name, descriptor, handle, bootstrapMethodArguments); 2477 currentOffset += 5; 2478 break; 2479 } 2480 case Opcodes.NEW: 2481 case Opcodes.ANEWARRAY: 2482 case Opcodes.CHECKCAST: 2483 case Opcodes.INSTANCEOF: 2484 methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer)); 2485 currentOffset += 3; 2486 break; 2487 case Opcodes.IINC: 2488 methodVisitor.visitIincInsn( 2489 classBuffer[currentOffset + 1] & 0xFF, classBuffer[currentOffset + 2]); 2490 currentOffset += 3; 2491 break; 2492 case Opcodes.MULTIANEWARRAY: 2493 methodVisitor.visitMultiANewArrayInsn( 2494 readClass(currentOffset + 1, charBuffer), classBuffer[currentOffset + 3] & 0xFF); 2495 currentOffset += 4; 2496 break; 2497 default: 2498 throw new AssertionError(); 2499 } 2500 2501 // Visit the runtime visible instruction annotations, if any. 2502 while (visibleTypeAnnotationOffsets != null 2503 && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length 2504 && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { 2505 if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { 2506 // Parse the target_type, target_info and target_path fields. 2507 int currentAnnotationOffset = 2508 readTypeAnnotationTarget( 2509 context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]); 2510 // Parse the type_index field. 2511 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 2512 currentAnnotationOffset += 2; 2513 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2514 readElementValues( 2515 methodVisitor.visitInsnAnnotation( 2516 context.currentTypeAnnotationTarget, 2517 context.currentTypeAnnotationTargetPath, 2518 annotationDescriptor, 2519 /* visible = */ true), 2520 currentAnnotationOffset, 2521 /* named = */ true, 2522 charBuffer); 2523 } 2524 currentVisibleTypeAnnotationBytecodeOffset = 2525 getTypeAnnotationBytecodeOffset( 2526 visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex); 2527 } 2528 2529 // Visit the runtime invisible instruction annotations, if any. 2530 while (invisibleTypeAnnotationOffsets != null 2531 && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length 2532 && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { 2533 if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { 2534 // Parse the target_type, target_info and target_path fields. 2535 int currentAnnotationOffset = 2536 readTypeAnnotationTarget( 2537 context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]); 2538 // Parse the type_index field. 2539 String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); 2540 currentAnnotationOffset += 2; 2541 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2542 readElementValues( 2543 methodVisitor.visitInsnAnnotation( 2544 context.currentTypeAnnotationTarget, 2545 context.currentTypeAnnotationTargetPath, 2546 annotationDescriptor, 2547 /* visible = */ false), 2548 currentAnnotationOffset, 2549 /* named = */ true, 2550 charBuffer); 2551 } 2552 currentInvisibleTypeAnnotationBytecodeOffset = 2553 getTypeAnnotationBytecodeOffset( 2554 invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex); 2555 } 2556 } 2557 if (labels[codeLength] != null) { 2558 methodVisitor.visitLabel(labels[codeLength]); 2559 } 2560 2561 // Visit LocalVariableTable and LocalVariableTypeTable attributes. 2562 if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { 2563 // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable. 2564 int[] typeTable = null; 2565 if (localVariableTypeTableOffset != 0) { 2566 typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3]; 2567 currentOffset = localVariableTypeTableOffset + 2; 2568 int typeTableIndex = typeTable.length; 2569 while (typeTableIndex > 0) { 2570 // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'. 2571 typeTable[--typeTableIndex] = currentOffset + 6; 2572 typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8); 2573 typeTable[--typeTableIndex] = readUnsignedShort(currentOffset); 2574 currentOffset += 10; 2575 } 2576 } 2577 int localVariableTableLength = readUnsignedShort(localVariableTableOffset); 2578 currentOffset = localVariableTableOffset + 2; 2579 while (localVariableTableLength-- > 0) { 2580 int startPc = readUnsignedShort(currentOffset); 2581 int length = readUnsignedShort(currentOffset + 2); 2582 String name = readUTF8(currentOffset + 4, charBuffer); 2583 String descriptor = readUTF8(currentOffset + 6, charBuffer); 2584 int index = readUnsignedShort(currentOffset + 8); 2585 currentOffset += 10; 2586 String signature = null; 2587 if (typeTable != null) { 2588 for (int i = 0; i < typeTable.length; i += 3) { 2589 if (typeTable[i] == startPc && typeTable[i + 1] == index) { 2590 signature = readUTF8(typeTable[i + 2], charBuffer); 2591 break; 2592 } 2593 } 2594 } 2595 methodVisitor.visitLocalVariable( 2596 name, descriptor, signature, labels[startPc], labels[startPc + length], index); 2597 } 2598 } 2599 2600 // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute. 2601 if (visibleTypeAnnotationOffsets != null) { 2602 for (int typeAnnotationOffset : visibleTypeAnnotationOffsets) { 2603 int targetType = readByte(typeAnnotationOffset); 2604 if (targetType == TypeReference.LOCAL_VARIABLE 2605 || targetType == TypeReference.RESOURCE_VARIABLE) { 2606 // Parse the target_type, target_info and target_path fields. 2607 currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); 2608 // Parse the type_index field. 2609 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2610 currentOffset += 2; 2611 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2612 readElementValues( 2613 methodVisitor.visitLocalVariableAnnotation( 2614 context.currentTypeAnnotationTarget, 2615 context.currentTypeAnnotationTargetPath, 2616 context.currentLocalVariableAnnotationRangeStarts, 2617 context.currentLocalVariableAnnotationRangeEnds, 2618 context.currentLocalVariableAnnotationRangeIndices, 2619 annotationDescriptor, 2620 /* visible = */ true), 2621 currentOffset, 2622 /* named = */ true, 2623 charBuffer); 2624 } 2625 } 2626 } 2627 2628 // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute. 2629 if (invisibleTypeAnnotationOffsets != null) { 2630 for (int typeAnnotationOffset : invisibleTypeAnnotationOffsets) { 2631 int targetType = readByte(typeAnnotationOffset); 2632 if (targetType == TypeReference.LOCAL_VARIABLE 2633 || targetType == TypeReference.RESOURCE_VARIABLE) { 2634 // Parse the target_type, target_info and target_path fields. 2635 currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); 2636 // Parse the type_index field. 2637 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2638 currentOffset += 2; 2639 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2640 readElementValues( 2641 methodVisitor.visitLocalVariableAnnotation( 2642 context.currentTypeAnnotationTarget, 2643 context.currentTypeAnnotationTargetPath, 2644 context.currentLocalVariableAnnotationRangeStarts, 2645 context.currentLocalVariableAnnotationRangeEnds, 2646 context.currentLocalVariableAnnotationRangeIndices, 2647 annotationDescriptor, 2648 /* visible = */ false), 2649 currentOffset, 2650 /* named = */ true, 2651 charBuffer); 2652 } 2653 } 2654 } 2655 2656 // Visit the non standard attributes. 2657 while (attributes != null) { 2658 // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. 2659 Attribute nextAttribute = attributes.nextAttribute; 2660 attributes.nextAttribute = null; 2661 methodVisitor.visitAttribute(attributes); 2662 attributes = nextAttribute; 2663 } 2664 2665 // Visit the max stack and max locals values. 2666 methodVisitor.visitMaxs(maxStack, maxLocals); 2667 } 2668 2669 /** 2670 * Handles the bytecode offset of the next instruction to be visited in {@link 2671 * #accept(ClassVisitor,int)}. This method is called just before the instruction and before its 2672 * associated label and stack map frame, if any. The default implementation of this method does 2673 * nothing. Subclasses can override this method to store the argument in a mutable field, for 2674 * instance, so that {@link MethodVisitor} instances can get the bytecode offset of each visited 2675 * instruction (if so, the usual concurrency issues related to mutable data should be addressed). 2676 * 2677 * @param bytecodeOffset the bytecode offset of the next instruction to be visited. 2678 */ 2679 protected void readBytecodeInstructionOffset(final int bytecodeOffset) { 2680 // Do nothing by default. 2681 } 2682 2683 /** 2684 * Returns the label corresponding to the given bytecode offset. The default implementation of 2685 * this method creates a label for the given offset if it has not been already created. 2686 * 2687 * @param bytecodeOffset a bytecode offset in a method. 2688 * @param labels the already created labels, indexed by their offset. If a label already exists 2689 * for bytecodeOffset this method must not create a new one. Otherwise it must store the new 2690 * label in this array. 2691 * @return a non null Label, which must be equal to labels[bytecodeOffset]. 2692 */ 2693 protected Label readLabel(final int bytecodeOffset, final Label[] labels) { 2694 if (labels[bytecodeOffset] == null) { 2695 labels[bytecodeOffset] = new Label(); 2696 } 2697 return labels[bytecodeOffset]; 2698 } 2699 2700 /** 2701 * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode 2702 * offset. The label is created with a call to {@link #readLabel} and its {@link 2703 * Label#FLAG_DEBUG_ONLY} flag is cleared. 2704 * 2705 * @param bytecodeOffset a bytecode offset in a method. 2706 * @param labels the already created labels, indexed by their offset. 2707 * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set. 2708 */ 2709 private Label createLabel(final int bytecodeOffset, final Label[] labels) { 2710 Label label = readLabel(bytecodeOffset, labels); 2711 label.flags &= ~Label.FLAG_DEBUG_ONLY; 2712 return label; 2713 } 2714 2715 /** 2716 * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already 2717 * existing label for the given bytecode offset (otherwise does nothing). The label is created 2718 * with a call to {@link #readLabel}. 2719 * 2720 * @param bytecodeOffset a bytecode offset in a method. 2721 * @param labels the already created labels, indexed by their offset. 2722 */ 2723 private void createDebugLabel(final int bytecodeOffset, final Label[] labels) { 2724 if (labels[bytecodeOffset] == null) { 2725 readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY; 2726 } 2727 } 2728 2729 // ---------------------------------------------------------------------------------------------- 2730 // Methods to parse annotations, type annotations and parameter annotations 2731 // ---------------------------------------------------------------------------------------------- 2732 2733 /** 2734 * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation 2735 * entry it contains, to find the corresponding labels, and to visit the try catch block 2736 * annotations. 2737 * 2738 * @param methodVisitor the method visitor to be used to visit the try catch block annotations. 2739 * @param context information about the class being parsed. 2740 * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations 2741 * attribute, excluding the attribute_info's attribute_name_index and attribute_length fields. 2742 * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute, 2743 * false it is a RuntimeInvisibleTypeAnnotations attribute. 2744 * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's 2745 * 'annotations' array field. 2746 */ 2747 private int[] readTypeAnnotations( 2748 final MethodVisitor methodVisitor, 2749 final Context context, 2750 final int runtimeTypeAnnotationsOffset, 2751 final boolean visible) { 2752 char[] charBuffer = context.charBuffer; 2753 int currentOffset = runtimeTypeAnnotationsOffset; 2754 // Read the num_annotations field and create an array to store the type_annotation offsets. 2755 int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)]; 2756 currentOffset += 2; 2757 // Parse the 'annotations' array field. 2758 for (int i = 0; i < typeAnnotationsOffsets.length; ++i) { 2759 typeAnnotationsOffsets[i] = currentOffset; 2760 // Parse the type_annotation's target_type and the target_info fields. The size of the 2761 // target_info field depends on the value of target_type. 2762 int targetType = readInt(currentOffset); 2763 switch (targetType >>> 24) { 2764 case TypeReference.LOCAL_VARIABLE: 2765 case TypeReference.RESOURCE_VARIABLE: 2766 // A localvar_target has a variable size, which depends on the value of their table_length 2767 // field. It also references bytecode offsets, for which we need labels. 2768 int tableLength = readUnsignedShort(currentOffset + 1); 2769 currentOffset += 3; 2770 while (tableLength-- > 0) { 2771 int startPc = readUnsignedShort(currentOffset); 2772 int length = readUnsignedShort(currentOffset + 2); 2773 // Skip the index field (2 bytes). 2774 currentOffset += 6; 2775 createLabel(startPc, context.currentMethodLabels); 2776 createLabel(startPc + length, context.currentMethodLabels); 2777 } 2778 break; 2779 case TypeReference.CAST: 2780 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 2781 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 2782 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 2783 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 2784 currentOffset += 4; 2785 break; 2786 case TypeReference.CLASS_EXTENDS: 2787 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 2788 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 2789 case TypeReference.THROWS: 2790 case TypeReference.EXCEPTION_PARAMETER: 2791 case TypeReference.INSTANCEOF: 2792 case TypeReference.NEW: 2793 case TypeReference.CONSTRUCTOR_REFERENCE: 2794 case TypeReference.METHOD_REFERENCE: 2795 currentOffset += 3; 2796 break; 2797 case TypeReference.CLASS_TYPE_PARAMETER: 2798 case TypeReference.METHOD_TYPE_PARAMETER: 2799 case TypeReference.METHOD_FORMAL_PARAMETER: 2800 case TypeReference.FIELD: 2801 case TypeReference.METHOD_RETURN: 2802 case TypeReference.METHOD_RECEIVER: 2803 default: 2804 // TypeReference type which can't be used in Code attribute, or which is unknown. 2805 throw new IllegalArgumentException(); 2806 } 2807 // Parse the rest of the type_annotation structure, starting with the target_path structure 2808 // (whose size depends on its path_length field). 2809 int pathLength = readByte(currentOffset); 2810 if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) { 2811 // Parse the target_path structure and create a corresponding TypePath. 2812 TypePath path = pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); 2813 currentOffset += 1 + 2 * pathLength; 2814 // Parse the type_index field. 2815 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2816 currentOffset += 2; 2817 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2818 currentOffset = 2819 readElementValues( 2820 methodVisitor.visitTryCatchAnnotation( 2821 targetType & 0xFFFFFF00, path, annotationDescriptor, visible), 2822 currentOffset, 2823 /* named = */ true, 2824 charBuffer); 2825 } else { 2826 // We don't want to visit the other target_type annotations, so we just skip them (which 2827 // requires some parsing because the element_value_pairs array has a variable size). First, 2828 // skip the target_path structure: 2829 currentOffset += 3 + 2 * pathLength; 2830 // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them 2831 // with a null AnnotationVisitor). 2832 currentOffset = 2833 readElementValues( 2834 /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer); 2835 } 2836 } 2837 return typeAnnotationsOffsets; 2838 } 2839 2840 /** 2841 * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or 2842 * -1 if there is no such type_annotation of if it does not have a bytecode offset. 2843 * 2844 * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a 2845 * Runtime[In]VisibleTypeAnnotations attribute, or {@literal null}. 2846 * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets. 2847 * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1 2848 * if there is no such type_annotation of if it does not have a bytecode offset. 2849 */ 2850 private int getTypeAnnotationBytecodeOffset( 2851 final int[] typeAnnotationOffsets, final int typeAnnotationIndex) { 2852 if (typeAnnotationOffsets == null 2853 || typeAnnotationIndex >= typeAnnotationOffsets.length 2854 || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) { 2855 return -1; 2856 } 2857 return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1); 2858 } 2859 2860 /** 2861 * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info 2862 * and target_path (the result is stored in the given context), and returns the start offset of 2863 * the rest of the type_annotation structure. 2864 * 2865 * @param context information about the class being parsed. This is where the extracted 2866 * target_type and target_path must be stored. 2867 * @param typeAnnotationOffset the start offset of a type_annotation structure. 2868 * @return the start offset of the rest of the type_annotation structure. 2869 */ 2870 private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) { 2871 int currentOffset = typeAnnotationOffset; 2872 // Parse and store the target_type structure. 2873 int targetType = readInt(typeAnnotationOffset); 2874 switch (targetType >>> 24) { 2875 case TypeReference.CLASS_TYPE_PARAMETER: 2876 case TypeReference.METHOD_TYPE_PARAMETER: 2877 case TypeReference.METHOD_FORMAL_PARAMETER: 2878 targetType &= 0xFFFF0000; 2879 currentOffset += 2; 2880 break; 2881 case TypeReference.FIELD: 2882 case TypeReference.METHOD_RETURN: 2883 case TypeReference.METHOD_RECEIVER: 2884 targetType &= 0xFF000000; 2885 currentOffset += 1; 2886 break; 2887 case TypeReference.LOCAL_VARIABLE: 2888 case TypeReference.RESOURCE_VARIABLE: 2889 targetType &= 0xFF000000; 2890 int tableLength = readUnsignedShort(currentOffset + 1); 2891 currentOffset += 3; 2892 context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength]; 2893 context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength]; 2894 context.currentLocalVariableAnnotationRangeIndices = new int[tableLength]; 2895 for (int i = 0; i < tableLength; ++i) { 2896 int startPc = readUnsignedShort(currentOffset); 2897 int length = readUnsignedShort(currentOffset + 2); 2898 int index = readUnsignedShort(currentOffset + 4); 2899 currentOffset += 6; 2900 context.currentLocalVariableAnnotationRangeStarts[i] = 2901 createLabel(startPc, context.currentMethodLabels); 2902 context.currentLocalVariableAnnotationRangeEnds[i] = 2903 createLabel(startPc + length, context.currentMethodLabels); 2904 context.currentLocalVariableAnnotationRangeIndices[i] = index; 2905 } 2906 break; 2907 case TypeReference.CAST: 2908 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 2909 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 2910 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 2911 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 2912 targetType &= 0xFF0000FF; 2913 currentOffset += 4; 2914 break; 2915 case TypeReference.CLASS_EXTENDS: 2916 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 2917 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 2918 case TypeReference.THROWS: 2919 case TypeReference.EXCEPTION_PARAMETER: 2920 targetType &= 0xFFFFFF00; 2921 currentOffset += 3; 2922 break; 2923 case TypeReference.INSTANCEOF: 2924 case TypeReference.NEW: 2925 case TypeReference.CONSTRUCTOR_REFERENCE: 2926 case TypeReference.METHOD_REFERENCE: 2927 targetType &= 0xFF000000; 2928 currentOffset += 3; 2929 break; 2930 default: 2931 throw new IllegalArgumentException(); 2932 } 2933 context.currentTypeAnnotationTarget = targetType; 2934 // Parse and store the target_path structure. 2935 int pathLength = readByte(currentOffset); 2936 context.currentTypeAnnotationTargetPath = 2937 pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); 2938 // Return the start offset of the rest of the type_annotation structure. 2939 return currentOffset + 1 + 2 * pathLength; 2940 } 2941 2942 /** 2943 * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it. 2944 * 2945 * @param methodVisitor the visitor that must visit the parameter annotations. 2946 * @param context information about the class being parsed. 2947 * @param runtimeParameterAnnotationsOffset the start offset of a 2948 * Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's 2949 * attribute_name_index and attribute_length fields. 2950 * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations 2951 * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute. 2952 */ readParameterAnnotations( final MethodVisitor methodVisitor, final Context context, final int runtimeParameterAnnotationsOffset, final boolean visible)2953 private void readParameterAnnotations( 2954 final MethodVisitor methodVisitor, 2955 final Context context, 2956 final int runtimeParameterAnnotationsOffset, 2957 final boolean visible) { 2958 int currentOffset = runtimeParameterAnnotationsOffset; 2959 int numParameters = classFileBuffer[currentOffset++] & 0xFF; 2960 methodVisitor.visitAnnotableParameterCount(numParameters, visible); 2961 char[] charBuffer = context.charBuffer; 2962 for (int i = 0; i < numParameters; ++i) { 2963 int numAnnotations = readUnsignedShort(currentOffset); 2964 currentOffset += 2; 2965 while (numAnnotations-- > 0) { 2966 // Parse the type_index field. 2967 String annotationDescriptor = readUTF8(currentOffset, charBuffer); 2968 currentOffset += 2; 2969 // Parse num_element_value_pairs and element_value_pairs and visit these values. 2970 currentOffset = 2971 readElementValues( 2972 methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible), 2973 currentOffset, 2974 /* named = */ true, 2975 charBuffer); 2976 } 2977 } 2978 } 2979 2980 /** 2981 * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit 2982 * them. This method can also be used to read the values of the JVMS 'array_value' field of an 2983 * annotation's 'element_value'. 2984 * 2985 * @param annotationVisitor the visitor that must visit the values. 2986 * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index 2987 * field) or of an 'array_value' structure. 2988 * @param named if the annotation values are named or not. This should be true to parse the values 2989 * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an 2990 * annotation's element_value. 2991 * @param charBuffer the buffer used to read strings in the constant pool. 2992 * @return the end offset of the JVMS 'annotation' or 'array_value' structure. 2993 */ readElementValues( final AnnotationVisitor annotationVisitor, final int annotationOffset, final boolean named, final char[] charBuffer)2994 private int readElementValues( 2995 final AnnotationVisitor annotationVisitor, 2996 final int annotationOffset, 2997 final boolean named, 2998 final char[] charBuffer) { 2999 int currentOffset = annotationOffset; 3000 // Read the num_element_value_pairs field (or num_values field for an array_value). 3001 int numElementValuePairs = readUnsignedShort(currentOffset); 3002 currentOffset += 2; 3003 if (named) { 3004 // Parse the element_value_pairs array. 3005 while (numElementValuePairs-- > 0) { 3006 String elementName = readUTF8(currentOffset, charBuffer); 3007 currentOffset = 3008 readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer); 3009 } 3010 } else { 3011 // Parse the array_value array. 3012 while (numElementValuePairs-- > 0) { 3013 currentOffset = 3014 readElementValue(annotationVisitor, currentOffset, /* elementName= */ null, charBuffer); 3015 } 3016 } 3017 if (annotationVisitor != null) { 3018 annotationVisitor.visitEnd(); 3019 } 3020 return currentOffset; 3021 } 3022 3023 /** 3024 * Reads a JVMS 'element_value' structure and makes the given visitor visit it. 3025 * 3026 * @param annotationVisitor the visitor that must visit the element_value structure. 3027 * @param elementValueOffset the start offset in {@link #classFileBuffer} of the element_value 3028 * structure to be read. 3029 * @param elementName the name of the element_value structure to be read, or {@literal null}. 3030 * @param charBuffer the buffer used to read strings in the constant pool. 3031 * @return the end offset of the JVMS 'element_value' structure. 3032 */ readElementValue( final AnnotationVisitor annotationVisitor, final int elementValueOffset, final String elementName, final char[] charBuffer)3033 private int readElementValue( 3034 final AnnotationVisitor annotationVisitor, 3035 final int elementValueOffset, 3036 final String elementName, 3037 final char[] charBuffer) { 3038 int currentOffset = elementValueOffset; 3039 if (annotationVisitor == null) { 3040 switch (classFileBuffer[currentOffset] & 0xFF) { 3041 case 'e': // enum_const_value 3042 return currentOffset + 5; 3043 case '@': // annotation_value 3044 return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer); 3045 case '[': // array_value 3046 return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer); 3047 default: 3048 return currentOffset + 3; 3049 } 3050 } 3051 switch (classFileBuffer[currentOffset++] & 0xFF) { 3052 case 'B': // const_value_index, CONSTANT_Integer 3053 annotationVisitor.visit( 3054 elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); 3055 currentOffset += 2; 3056 break; 3057 case 'C': // const_value_index, CONSTANT_Integer 3058 annotationVisitor.visit( 3059 elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); 3060 currentOffset += 2; 3061 break; 3062 case 'D': // const_value_index, CONSTANT_Double 3063 case 'F': // const_value_index, CONSTANT_Float 3064 case 'I': // const_value_index, CONSTANT_Integer 3065 case 'J': // const_value_index, CONSTANT_Long 3066 annotationVisitor.visit( 3067 elementName, readConst(readUnsignedShort(currentOffset), charBuffer)); 3068 currentOffset += 2; 3069 break; 3070 case 'S': // const_value_index, CONSTANT_Integer 3071 annotationVisitor.visit( 3072 elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); 3073 currentOffset += 2; 3074 break; 3075 3076 case 'Z': // const_value_index, CONSTANT_Integer 3077 annotationVisitor.visit( 3078 elementName, 3079 readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0 3080 ? Boolean.FALSE 3081 : Boolean.TRUE); 3082 currentOffset += 2; 3083 break; 3084 case 's': // const_value_index, CONSTANT_Utf8 3085 annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer)); 3086 currentOffset += 2; 3087 break; 3088 case 'e': // enum_const_value 3089 annotationVisitor.visitEnum( 3090 elementName, 3091 readUTF8(currentOffset, charBuffer), 3092 readUTF8(currentOffset + 2, charBuffer)); 3093 currentOffset += 4; 3094 break; 3095 case 'c': // class_info 3096 annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer))); 3097 currentOffset += 2; 3098 break; 3099 case '@': // annotation_value 3100 currentOffset = 3101 readElementValues( 3102 annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)), 3103 currentOffset + 2, 3104 true, 3105 charBuffer); 3106 break; 3107 case '[': // array_value 3108 int numValues = readUnsignedShort(currentOffset); 3109 currentOffset += 2; 3110 if (numValues == 0) { 3111 return readElementValues( 3112 annotationVisitor.visitArray(elementName), 3113 currentOffset - 2, 3114 /* named = */ false, 3115 charBuffer); 3116 } 3117 switch (classFileBuffer[currentOffset] & 0xFF) { 3118 case 'B': 3119 byte[] byteValues = new byte[numValues]; 3120 for (int i = 0; i < numValues; i++) { 3121 byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3122 currentOffset += 3; 3123 } 3124 annotationVisitor.visit(elementName, byteValues); 3125 break; 3126 case 'Z': 3127 boolean[] booleanValues = new boolean[numValues]; 3128 for (int i = 0; i < numValues; i++) { 3129 booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0; 3130 currentOffset += 3; 3131 } 3132 annotationVisitor.visit(elementName, booleanValues); 3133 break; 3134 case 'S': 3135 short[] shortValues = new short[numValues]; 3136 for (int i = 0; i < numValues; i++) { 3137 shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3138 currentOffset += 3; 3139 } 3140 annotationVisitor.visit(elementName, shortValues); 3141 break; 3142 case 'C': 3143 char[] charValues = new char[numValues]; 3144 for (int i = 0; i < numValues; i++) { 3145 charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3146 currentOffset += 3; 3147 } 3148 annotationVisitor.visit(elementName, charValues); 3149 break; 3150 case 'I': 3151 int[] intValues = new int[numValues]; 3152 for (int i = 0; i < numValues; i++) { 3153 intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3154 currentOffset += 3; 3155 } 3156 annotationVisitor.visit(elementName, intValues); 3157 break; 3158 case 'J': 3159 long[] longValues = new long[numValues]; 3160 for (int i = 0; i < numValues; i++) { 3161 longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); 3162 currentOffset += 3; 3163 } 3164 annotationVisitor.visit(elementName, longValues); 3165 break; 3166 case 'F': 3167 float[] floatValues = new float[numValues]; 3168 for (int i = 0; i < numValues; i++) { 3169 floatValues[i] = 3170 Float.intBitsToFloat( 3171 readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); 3172 currentOffset += 3; 3173 } 3174 annotationVisitor.visit(elementName, floatValues); 3175 break; 3176 case 'D': 3177 double[] doubleValues = new double[numValues]; 3178 for (int i = 0; i < numValues; i++) { 3179 doubleValues[i] = 3180 Double.longBitsToDouble( 3181 readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); 3182 currentOffset += 3; 3183 } 3184 annotationVisitor.visit(elementName, doubleValues); 3185 break; 3186 default: 3187 currentOffset = 3188 readElementValues( 3189 annotationVisitor.visitArray(elementName), 3190 currentOffset - 2, 3191 /* named = */ false, 3192 charBuffer); 3193 break; 3194 } 3195 break; 3196 default: 3197 throw new IllegalArgumentException(); 3198 } 3199 return currentOffset; 3200 } 3201 3202 // ---------------------------------------------------------------------------------------------- 3203 // Methods to parse stack map frames 3204 // ---------------------------------------------------------------------------------------------- 3205 3206 /** 3207 * Computes the implicit frame of the method currently being parsed (as defined in the given 3208 * {@link Context}) and stores it in the given context. 3209 * 3210 * @param context information about the class being parsed. 3211 */ computeImplicitFrame(final Context context)3212 private void computeImplicitFrame(final Context context) { 3213 String methodDescriptor = context.currentMethodDescriptor; 3214 Object[] locals = context.currentFrameLocalTypes; 3215 int numLocal = 0; 3216 if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) { 3217 if ("<init>".equals(context.currentMethodName)) { 3218 locals[numLocal++] = Opcodes.UNINITIALIZED_THIS; 3219 } else { 3220 locals[numLocal++] = readClass(header + 2, context.charBuffer); 3221 } 3222 } 3223 // Parse the method descriptor, one argument type descriptor at each iteration. Start by 3224 // skipping the first method descriptor character, which is always '('. 3225 int currentMethodDescritorOffset = 1; 3226 while (true) { 3227 int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset; 3228 switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) { 3229 case 'Z': 3230 case 'C': 3231 case 'B': 3232 case 'S': 3233 case 'I': 3234 locals[numLocal++] = Opcodes.INTEGER; 3235 break; 3236 case 'F': 3237 locals[numLocal++] = Opcodes.FLOAT; 3238 break; 3239 case 'J': 3240 locals[numLocal++] = Opcodes.LONG; 3241 break; 3242 case 'D': 3243 locals[numLocal++] = Opcodes.DOUBLE; 3244 break; 3245 case '[': 3246 while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { 3247 ++currentMethodDescritorOffset; 3248 } 3249 if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') { 3250 ++currentMethodDescritorOffset; 3251 while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { 3252 ++currentMethodDescritorOffset; 3253 } 3254 } 3255 locals[numLocal++] = 3256 methodDescriptor.substring( 3257 currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); 3258 break; 3259 case 'L': 3260 while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { 3261 ++currentMethodDescritorOffset; 3262 } 3263 locals[numLocal++] = 3264 methodDescriptor.substring( 3265 currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); 3266 break; 3267 default: 3268 context.currentFrameLocalCount = numLocal; 3269 return; 3270 } 3271 } 3272 } 3273 3274 /** 3275 * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context} 3276 * object. This method can also be used to read a full_frame structure, excluding its frame_type 3277 * field (this is used to parse the legacy StackMap attributes). 3278 * 3279 * @param stackMapFrameOffset the start offset in {@link #classFileBuffer} of the 3280 * stack_map_frame_value structure to be read, or the start offset of a full_frame structure 3281 * (excluding its frame_type field). 3282 * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame' 3283 * structure without its frame_type field. 3284 * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}. 3285 * @param context where the parsed stack map frame must be stored. 3286 * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure. 3287 */ readStackMapFrame( final int stackMapFrameOffset, final boolean compressed, final boolean expand, final Context context)3288 private int readStackMapFrame( 3289 final int stackMapFrameOffset, 3290 final boolean compressed, 3291 final boolean expand, 3292 final Context context) { 3293 int currentOffset = stackMapFrameOffset; 3294 final char[] charBuffer = context.charBuffer; 3295 final Label[] labels = context.currentMethodLabels; 3296 int frameType; 3297 if (compressed) { 3298 // Read the frame_type field. 3299 frameType = classFileBuffer[currentOffset++] & 0xFF; 3300 } else { 3301 frameType = Frame.FULL_FRAME; 3302 context.currentFrameOffset = -1; 3303 } 3304 int offsetDelta; 3305 context.currentFrameLocalCountDelta = 0; 3306 if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) { 3307 offsetDelta = frameType; 3308 context.currentFrameType = Opcodes.F_SAME; 3309 context.currentFrameStackCount = 0; 3310 } else if (frameType < Frame.RESERVED) { 3311 offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME; 3312 currentOffset = 3313 readVerificationTypeInfo( 3314 currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); 3315 context.currentFrameType = Opcodes.F_SAME1; 3316 context.currentFrameStackCount = 1; 3317 } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 3318 offsetDelta = readUnsignedShort(currentOffset); 3319 currentOffset += 2; 3320 if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 3321 currentOffset = 3322 readVerificationTypeInfo( 3323 currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); 3324 context.currentFrameType = Opcodes.F_SAME1; 3325 context.currentFrameStackCount = 1; 3326 } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) { 3327 context.currentFrameType = Opcodes.F_CHOP; 3328 context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType; 3329 context.currentFrameLocalCount -= context.currentFrameLocalCountDelta; 3330 context.currentFrameStackCount = 0; 3331 } else if (frameType == Frame.SAME_FRAME_EXTENDED) { 3332 context.currentFrameType = Opcodes.F_SAME; 3333 context.currentFrameStackCount = 0; 3334 } else if (frameType < Frame.FULL_FRAME) { 3335 int local = expand ? context.currentFrameLocalCount : 0; 3336 for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) { 3337 currentOffset = 3338 readVerificationTypeInfo( 3339 currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels); 3340 } 3341 context.currentFrameType = Opcodes.F_APPEND; 3342 context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED; 3343 context.currentFrameLocalCount += context.currentFrameLocalCountDelta; 3344 context.currentFrameStackCount = 0; 3345 } else { 3346 final int numberOfLocals = readUnsignedShort(currentOffset); 3347 currentOffset += 2; 3348 context.currentFrameType = Opcodes.F_FULL; 3349 context.currentFrameLocalCountDelta = numberOfLocals; 3350 context.currentFrameLocalCount = numberOfLocals; 3351 for (int local = 0; local < numberOfLocals; ++local) { 3352 currentOffset = 3353 readVerificationTypeInfo( 3354 currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels); 3355 } 3356 final int numberOfStackItems = readUnsignedShort(currentOffset); 3357 currentOffset += 2; 3358 context.currentFrameStackCount = numberOfStackItems; 3359 for (int stack = 0; stack < numberOfStackItems; ++stack) { 3360 currentOffset = 3361 readVerificationTypeInfo( 3362 currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels); 3363 } 3364 } 3365 } else { 3366 throw new IllegalArgumentException(); 3367 } 3368 context.currentFrameOffset += offsetDelta + 1; 3369 createLabel(context.currentFrameOffset, labels); 3370 return currentOffset; 3371 } 3372 3373 /** 3374 * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given 3375 * array. 3376 * 3377 * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to 3378 * read. 3379 * @param frame the array where the parsed type must be stored. 3380 * @param index the index in 'frame' where the parsed type must be stored. 3381 * @param charBuffer the buffer used to read strings in the constant pool. 3382 * @param labels the labels of the method currently being parsed, indexed by their offset. If the 3383 * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is 3384 * stored in this array if it does not already exist. 3385 * @return the end offset of the JVMS 'verification_type_info' structure. 3386 */ readVerificationTypeInfo( final int verificationTypeInfoOffset, final Object[] frame, final int index, final char[] charBuffer, final Label[] labels)3387 private int readVerificationTypeInfo( 3388 final int verificationTypeInfoOffset, 3389 final Object[] frame, 3390 final int index, 3391 final char[] charBuffer, 3392 final Label[] labels) { 3393 int currentOffset = verificationTypeInfoOffset; 3394 int tag = classFileBuffer[currentOffset++] & 0xFF; 3395 switch (tag) { 3396 case Frame.ITEM_TOP: 3397 frame[index] = Opcodes.TOP; 3398 break; 3399 case Frame.ITEM_INTEGER: 3400 frame[index] = Opcodes.INTEGER; 3401 break; 3402 case Frame.ITEM_FLOAT: 3403 frame[index] = Opcodes.FLOAT; 3404 break; 3405 case Frame.ITEM_DOUBLE: 3406 frame[index] = Opcodes.DOUBLE; 3407 break; 3408 case Frame.ITEM_LONG: 3409 frame[index] = Opcodes.LONG; 3410 break; 3411 case Frame.ITEM_NULL: 3412 frame[index] = Opcodes.NULL; 3413 break; 3414 case Frame.ITEM_UNINITIALIZED_THIS: 3415 frame[index] = Opcodes.UNINITIALIZED_THIS; 3416 break; 3417 case Frame.ITEM_OBJECT: 3418 frame[index] = readClass(currentOffset, charBuffer); 3419 currentOffset += 2; 3420 break; 3421 case Frame.ITEM_UNINITIALIZED: 3422 frame[index] = createLabel(readUnsignedShort(currentOffset), labels); 3423 currentOffset += 2; 3424 break; 3425 default: 3426 throw new IllegalArgumentException(); 3427 } 3428 return currentOffset; 3429 } 3430 3431 // ---------------------------------------------------------------------------------------------- 3432 // Methods to parse attributes 3433 // ---------------------------------------------------------------------------------------------- 3434 3435 /** 3436 * Returns the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array 3437 * field entry. 3438 * 3439 * @return the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array 3440 * field entry. 3441 */ getFirstAttributeOffset()3442 final int getFirstAttributeOffset() { 3443 // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes 3444 // each), as well as the interfaces array field (2 bytes per interface). 3445 int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2; 3446 3447 // Read the fields_count field. 3448 int fieldsCount = readUnsignedShort(currentOffset); 3449 currentOffset += 2; 3450 // Skip the 'fields' array field. 3451 while (fieldsCount-- > 0) { 3452 // Invariant: currentOffset is the offset of a field_info structure. 3453 // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the 3454 // attributes_count field. 3455 int attributesCount = readUnsignedShort(currentOffset + 6); 3456 currentOffset += 8; 3457 // Skip the 'attributes' array field. 3458 while (attributesCount-- > 0) { 3459 // Invariant: currentOffset is the offset of an attribute_info structure. 3460 // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip 3461 // this many bytes, plus 6 for the attribute_name_index and attribute_length fields 3462 // (yielding the total size of the attribute_info structure). 3463 currentOffset += 6 + readInt(currentOffset + 2); 3464 } 3465 } 3466 3467 // Skip the methods_count and 'methods' fields, using the same method as above. 3468 int methodsCount = readUnsignedShort(currentOffset); 3469 currentOffset += 2; 3470 while (methodsCount-- > 0) { 3471 int attributesCount = readUnsignedShort(currentOffset + 6); 3472 currentOffset += 8; 3473 while (attributesCount-- > 0) { 3474 currentOffset += 6 + readInt(currentOffset + 2); 3475 } 3476 } 3477 3478 // Skip the ClassFile's attributes_count field. 3479 return currentOffset + 2; 3480 } 3481 3482 /** 3483 * Reads the BootstrapMethods attribute to compute the offset of each bootstrap method. 3484 * 3485 * @param maxStringLength a conservative estimate of the maximum length of the strings contained 3486 * in the constant pool of the class. 3487 * @return the offsets of the bootstrap methods. 3488 */ readBootstrapMethodsAttribute(final int maxStringLength)3489 private int[] readBootstrapMethodsAttribute(final int maxStringLength) { 3490 char[] charBuffer = new char[maxStringLength]; 3491 int currentAttributeOffset = getFirstAttributeOffset(); 3492 for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { 3493 // Read the attribute_info's attribute_name and attribute_length fields. 3494 String attributeName = readUTF8(currentAttributeOffset, charBuffer); 3495 int attributeLength = readInt(currentAttributeOffset + 2); 3496 currentAttributeOffset += 6; 3497 if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { 3498 // Read the num_bootstrap_methods field and create an array of this size. 3499 int[] result = new int[readUnsignedShort(currentAttributeOffset)]; 3500 // Compute and store the offset of each 'bootstrap_methods' array field entry. 3501 int currentBootstrapMethodOffset = currentAttributeOffset + 2; 3502 for (int j = 0; j < result.length; ++j) { 3503 result[j] = currentBootstrapMethodOffset; 3504 // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), 3505 // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). 3506 currentBootstrapMethodOffset += 3507 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; 3508 } 3509 return result; 3510 } 3511 currentAttributeOffset += attributeLength; 3512 } 3513 throw new IllegalArgumentException(); 3514 } 3515 3516 /** 3517 * Reads a non standard JVMS 'attribute' structure in {@link #classFileBuffer}. 3518 * 3519 * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of 3520 * the class. Any attribute whose type is not equal to the type of one the prototypes will not 3521 * be parsed: its byte array value will be passed unchanged to the ClassWriter. 3522 * @param type the type of the attribute. 3523 * @param offset the start offset of the JVMS 'attribute' structure in {@link #classFileBuffer}. 3524 * The 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into 3525 * account here. 3526 * @param length the length of the attribute's content (excluding the 6 attribute header bytes). 3527 * @param charBuffer the buffer to be used to read strings in the constant pool. 3528 * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link 3529 * #classFileBuffer}, or -1 if the attribute to be read is not a code attribute. The 6 3530 * attribute header bytes (attribute_name_index and attribute_length) are not taken into 3531 * account here. 3532 * @param labels the labels of the method's code, or {@literal null} if the attribute to be read 3533 * is not a code attribute. 3534 * @return the attribute that has been read. 3535 */ readAttribute( final Attribute[] attributePrototypes, final String type, final int offset, final int length, final char[] charBuffer, final int codeAttributeOffset, final Label[] labels)3536 private Attribute readAttribute( 3537 final Attribute[] attributePrototypes, 3538 final String type, 3539 final int offset, 3540 final int length, 3541 final char[] charBuffer, 3542 final int codeAttributeOffset, 3543 final Label[] labels) { 3544 for (Attribute attributePrototype : attributePrototypes) { 3545 if (attributePrototype.type.equals(type)) { 3546 return attributePrototype.read( 3547 this, offset, length, charBuffer, codeAttributeOffset, labels); 3548 } 3549 } 3550 return new Attribute(type).read(this, offset, length, null, -1, null); 3551 } 3552 3553 // ----------------------------------------------------------------------------------------------- 3554 // Utility methods: low level parsing 3555 // ----------------------------------------------------------------------------------------------- 3556 3557 /** 3558 * Returns the number of entries in the class's constant pool table. 3559 * 3560 * @return the number of entries in the class's constant pool table. 3561 */ getItemCount()3562 public int getItemCount() { 3563 return cpInfoOffsets.length; 3564 } 3565 3566 /** 3567 * Returns the start offset in this {@link ClassReader} of a JVMS 'cp_info' structure (i.e. a 3568 * constant pool entry), plus one. <i>This method is intended for {@link Attribute} sub classes, 3569 * and is normally not needed by class generators or adapters.</i> 3570 * 3571 * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool 3572 * table. 3573 * @return the start offset in this {@link ClassReader} of the corresponding JVMS 'cp_info' 3574 * structure, plus one. 3575 */ getItem(final int constantPoolEntryIndex)3576 public int getItem(final int constantPoolEntryIndex) { 3577 return cpInfoOffsets[constantPoolEntryIndex]; 3578 } 3579 3580 /** 3581 * Returns a conservative estimate of the maximum length of the strings contained in the class's 3582 * constant pool table. 3583 * 3584 * @return a conservative estimate of the maximum length of the strings contained in the class's 3585 * constant pool table. 3586 */ getMaxStringLength()3587 public int getMaxStringLength() { 3588 return maxStringLength; 3589 } 3590 3591 /** 3592 * Reads a byte value in this {@link ClassReader}. <i>This method is intended for {@link 3593 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3594 * 3595 * @param offset the start offset of the value to be read in this {@link ClassReader}. 3596 * @return the read value. 3597 */ readByte(final int offset)3598 public int readByte(final int offset) { 3599 return classFileBuffer[offset] & 0xFF; 3600 } 3601 3602 /** 3603 * Reads an unsigned short value in this {@link ClassReader}. <i>This method is intended for 3604 * {@link Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3605 * 3606 * @param offset the start index of the value to be read in this {@link ClassReader}. 3607 * @return the read value. 3608 */ readUnsignedShort(final int offset)3609 public int readUnsignedShort(final int offset) { 3610 byte[] classBuffer = classFileBuffer; 3611 return ((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF); 3612 } 3613 3614 /** 3615 * Reads a signed short value in this {@link ClassReader}. <i>This method is intended for {@link 3616 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3617 * 3618 * @param offset the start offset of the value to be read in this {@link ClassReader}. 3619 * @return the read value. 3620 */ readShort(final int offset)3621 public short readShort(final int offset) { 3622 byte[] classBuffer = classFileBuffer; 3623 return (short) (((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF)); 3624 } 3625 3626 /** 3627 * Reads a signed int 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 */ readInt(final int offset)3633 public int readInt(final int offset) { 3634 byte[] classBuffer = classFileBuffer; 3635 return ((classBuffer[offset] & 0xFF) << 24) 3636 | ((classBuffer[offset + 1] & 0xFF) << 16) 3637 | ((classBuffer[offset + 2] & 0xFF) << 8) 3638 | (classBuffer[offset + 3] & 0xFF); 3639 } 3640 3641 /** 3642 * Reads a signed long value in this {@link ClassReader}. <i>This method is intended for {@link 3643 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 3644 * 3645 * @param offset the start offset of the value to be read in this {@link ClassReader}. 3646 * @return the read value. 3647 */ readLong(final int offset)3648 public long readLong(final int offset) { 3649 long l1 = readInt(offset); 3650 long l0 = readInt(offset + 4) & 0xFFFFFFFFL; 3651 return (l1 << 32) | l0; 3652 } 3653 3654 /** 3655 * Reads a CONSTANT_Utf8 constant pool entry in this {@link ClassReader}. <i>This method is 3656 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3657 * adapters.</i> 3658 * 3659 * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose 3660 * value is the index of a CONSTANT_Utf8 entry in the class's constant pool table. 3661 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3662 * large. It is not automatically resized. 3663 * @return the String corresponding to the specified CONSTANT_Utf8 entry. 3664 */ 3665 // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). readUTF8(final int offset, final char[] charBuffer)3666 public String readUTF8(final int offset, final char[] charBuffer) { 3667 int constantPoolEntryIndex = readUnsignedShort(offset); 3668 if (offset == 0 || constantPoolEntryIndex == 0) { 3669 return null; 3670 } 3671 return readUtf(constantPoolEntryIndex, charBuffer); 3672 } 3673 3674 /** 3675 * Reads a CONSTANT_Utf8 constant pool entry in {@link #classFileBuffer}. 3676 * 3677 * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool 3678 * table. 3679 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3680 * large. It is not automatically resized. 3681 * @return the String corresponding to the specified CONSTANT_Utf8 entry. 3682 */ readUtf(final int constantPoolEntryIndex, final char[] charBuffer)3683 final String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) { 3684 String value = constantUtf8Values[constantPoolEntryIndex]; 3685 if (value != null) { 3686 return value; 3687 } 3688 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; 3689 return constantUtf8Values[constantPoolEntryIndex] = 3690 readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); 3691 } 3692 3693 /** 3694 * Reads an UTF8 string in {@link #classFileBuffer}. 3695 * 3696 * @param utfOffset the start offset of the UTF8 string to be read. 3697 * @param utfLength the length of the UTF8 string to be read. 3698 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3699 * large. It is not automatically resized. 3700 * @return the String corresponding to the specified UTF8 string. 3701 */ readUtf(final int utfOffset, final int utfLength, final char[] charBuffer)3702 private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) { 3703 int currentOffset = utfOffset; 3704 int endOffset = currentOffset + utfLength; 3705 int strLength = 0; 3706 byte[] classBuffer = classFileBuffer; 3707 while (currentOffset < endOffset) { 3708 int currentByte = classBuffer[currentOffset++]; 3709 if ((currentByte & 0x80) == 0) { 3710 charBuffer[strLength++] = (char) (currentByte & 0x7F); 3711 } else if ((currentByte & 0xE0) == 0xC0) { 3712 charBuffer[strLength++] = 3713 (char) (((currentByte & 0x1F) << 6) + (classBuffer[currentOffset++] & 0x3F)); 3714 } else { 3715 charBuffer[strLength++] = 3716 (char) 3717 (((currentByte & 0xF) << 12) 3718 + ((classBuffer[currentOffset++] & 0x3F) << 6) 3719 + (classBuffer[currentOffset++] & 0x3F)); 3720 } 3721 } 3722 return new String(charBuffer, 0, strLength); 3723 } 3724 3725 /** 3726 * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or 3727 * CONSTANT_Package constant pool entry in {@link #classFileBuffer}. <i>This method is intended 3728 * for {@link Attribute} sub classes, and is normally not needed by class generators or 3729 * adapters.</i> 3730 * 3731 * @param offset the start offset of an unsigned short value in {@link #classFileBuffer}, whose 3732 * value is the index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, 3733 * CONSTANT_Module or CONSTANT_Package entry in class's constant pool table. 3734 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently 3735 * large. It is not automatically resized. 3736 * @return the String corresponding to the specified constant pool entry. 3737 */ readStringish(final int offset, final char[] charBuffer)3738 private String readStringish(final int offset, final char[] charBuffer) { 3739 // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry 3740 // designated by the first two bytes of this cp_info. 3741 return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); 3742 } 3743 3744 /** 3745 * Reads a CONSTANT_Class 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_Class 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_Class entry. 3754 */ readClass(final int offset, final char[] charBuffer)3755 public String readClass(final int offset, final char[] charBuffer) { 3756 return readStringish(offset, charBuffer); 3757 } 3758 3759 /** 3760 * Reads a CONSTANT_Module 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_Module 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_Module entry. 3769 */ readModule(final int offset, final char[] charBuffer)3770 public String readModule(final int offset, final char[] charBuffer) { 3771 return readStringish(offset, charBuffer); 3772 } 3773 3774 /** 3775 * Reads a CONSTANT_Package constant pool entry in this {@link ClassReader}. <i>This method is 3776 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3777 * adapters.</i> 3778 * 3779 * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose 3780 * value is the index of a CONSTANT_Package entry in class's constant pool table. 3781 * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently 3782 * large. It is not automatically resized. 3783 * @return the String corresponding to the specified CONSTANT_Package entry. 3784 */ readPackage(final int offset, final char[] charBuffer)3785 public String readPackage(final int offset, final char[] charBuffer) { 3786 return readStringish(offset, charBuffer); 3787 } 3788 3789 /** 3790 * Reads a CONSTANT_Dynamic constant pool entry in {@link #classFileBuffer}. 3791 * 3792 * @param constantPoolEntryIndex the index of a CONSTANT_Dynamic entry in the class's constant 3793 * pool table. 3794 * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently 3795 * large. It is not automatically resized. 3796 * @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry. 3797 */ readConstantDynamic( final int constantPoolEntryIndex, final char[] charBuffer)3798 private ConstantDynamic readConstantDynamic( 3799 final int constantPoolEntryIndex, final char[] charBuffer) { 3800 ConstantDynamic constantDynamic = constantDynamicValues[constantPoolEntryIndex]; 3801 if (constantDynamic != null) { 3802 return constantDynamic; 3803 } 3804 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; 3805 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; 3806 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 3807 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 3808 int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; 3809 Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 3810 Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; 3811 bootstrapMethodOffset += 4; 3812 for (int i = 0; i < bootstrapMethodArguments.length; i++) { 3813 bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); 3814 bootstrapMethodOffset += 2; 3815 } 3816 return constantDynamicValues[constantPoolEntryIndex] = 3817 new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments); 3818 } 3819 3820 /** 3821 * Reads a numeric or string constant pool entry in this {@link ClassReader}. <i>This method is 3822 * intended for {@link Attribute} sub classes, and is normally not needed by class generators or 3823 * adapters.</i> 3824 * 3825 * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, 3826 * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, 3827 * CONSTANT_MethodHandle or CONSTANT_Dynamic entry in the class's constant pool. 3828 * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently 3829 * large. It is not automatically resized. 3830 * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, 3831 * {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified 3832 * constant pool entry. 3833 */ readConst(final int constantPoolEntryIndex, final char[] charBuffer)3834 public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) { 3835 int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; 3836 switch (classFileBuffer[cpInfoOffset - 1]) { 3837 case Symbol.CONSTANT_INTEGER_TAG: 3838 return readInt(cpInfoOffset); 3839 case Symbol.CONSTANT_FLOAT_TAG: 3840 return Float.intBitsToFloat(readInt(cpInfoOffset)); 3841 case Symbol.CONSTANT_LONG_TAG: 3842 return readLong(cpInfoOffset); 3843 case Symbol.CONSTANT_DOUBLE_TAG: 3844 return Double.longBitsToDouble(readLong(cpInfoOffset)); 3845 case Symbol.CONSTANT_CLASS_TAG: 3846 return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); 3847 case Symbol.CONSTANT_STRING_TAG: 3848 return readUTF8(cpInfoOffset, charBuffer); 3849 case Symbol.CONSTANT_METHOD_TYPE_TAG: 3850 return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); 3851 case Symbol.CONSTANT_METHOD_HANDLE_TAG: 3852 int referenceKind = readByte(cpInfoOffset); 3853 int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; 3854 int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; 3855 String owner = readClass(referenceCpInfoOffset, charBuffer); 3856 String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); 3857 String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); 3858 boolean isInterface = 3859 classFileBuffer[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; 3860 return new Handle(referenceKind, owner, name, descriptor, isInterface); 3861 case Symbol.CONSTANT_DYNAMIC_TAG: 3862 return readConstantDynamic(constantPoolEntryIndex, charBuffer); 3863 default: 3864 throw new IllegalArgumentException(); 3865 } 3866 } 3867 } 3868