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