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