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