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