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