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