001// ASM: a very small and fast Java bytecode manipulation framework 002// Copyright (c) 2000-2011 INRIA, France Telecom 003// All rights reserved. 004// 005// Redistribution and use in source and binary forms, with or without 006// modification, are permitted provided that the following conditions 007// are met: 008// 1. Redistributions of source code must retain the above copyright 009// notice, this list of conditions and the following disclaimer. 010// 2. Redistributions in binary form must reproduce the above copyright 011// notice, this list of conditions and the following disclaimer in the 012// documentation and/or other materials provided with the distribution. 013// 3. Neither the name of the copyright holders nor the names of its 014// contributors may be used to endorse or promote products derived from 015// this software without specific prior written permission. 016// 017// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 018// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 019// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 020// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 021// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 022// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 023// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 024// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 025// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 026// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 027// THE POSSIBILITY OF SUCH DAMAGE. 028package org.springframework.asm; 029 030/** 031 * A {@link ClassVisitor} that generates a corresponding ClassFile structure, as defined in the Java 032 * Virtual Machine Specification (JVMS). It can be used alone, to generate a Java class "from 033 * scratch", or with one or more {@link ClassReader} and adapter {@link ClassVisitor} to generate a 034 * modified class from one or more existing Java classes. 035 * 036 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a> 037 * @author Eric Bruneton 038 */ 039public class ClassWriter extends ClassVisitor { 040 041 /** 042 * A flag to automatically compute the maximum stack size and the maximum number of local 043 * variables of methods. If this flag is set, then the arguments of the {@link 044 * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link 045 * #visitMethod} method will be ignored, and computed automatically from the signature and the 046 * bytecode of each method. 047 * 048 * <p><b>Note:</b> for classes whose version is {@link Opcodes#V1_7} of more, this option requires 049 * valid stack map frames. The maximum stack size is then computed from these frames, and from the 050 * bytecode instructions in between. If stack map frames are not present or must be recomputed, 051 * used {@link #COMPUTE_FRAMES} instead. 052 * 053 * @see #ClassWriter(int) 054 */ 055 public static final int COMPUTE_MAXS = 1; 056 057 /** 058 * A flag to automatically compute the stack map frames of methods from scratch. If this flag is 059 * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack 060 * map frames are recomputed from the methods bytecode. The arguments of the {@link 061 * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other 062 * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}. 063 * 064 * @see #ClassWriter(int) 065 */ 066 public static final int COMPUTE_FRAMES = 2; 067 068 // Note: fields are ordered as in the ClassFile structure, and those related to attributes are 069 // ordered as in Section 4.7 of the JVMS. 070 071 /** 072 * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is 073 * stored in the 16 most significant bits, and major_version in the 16 least significant bits. 074 */ 075 private int version; 076 077 /** The symbol table for this class (contains the constant_pool and the BootstrapMethods). */ 078 private final SymbolTable symbolTable; 079 080 /** 081 * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific 082 * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the 083 * ClassFile structure. 084 */ 085 private int accessFlags; 086 087 /** The this_class field of the JVMS ClassFile structure. */ 088 private int thisClass; 089 090 /** The super_class field of the JVMS ClassFile structure. */ 091 private int superClass; 092 093 /** The interface_count field of the JVMS ClassFile structure. */ 094 private int interfaceCount; 095 096 /** The 'interfaces' array of the JVMS ClassFile structure. */ 097 private int[] interfaces; 098 099 /** 100 * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their 101 * {@link FieldWriter#fv} field. This field stores the first element of this list. 102 */ 103 private FieldWriter firstField; 104 105 /** 106 * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their 107 * {@link FieldWriter#fv} field. This field stores the last element of this list. 108 */ 109 private FieldWriter lastField; 110 111 /** 112 * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their 113 * {@link MethodWriter#mv} field. This field stores the first element of this list. 114 */ 115 private MethodWriter firstMethod; 116 117 /** 118 * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their 119 * {@link MethodWriter#mv} field. This field stores the last element of this list. 120 */ 121 private MethodWriter lastMethod; 122 123 /** The number_of_classes field of the InnerClasses attribute, or 0. */ 124 private int numberOfInnerClasses; 125 126 /** The 'classes' array of the InnerClasses attribute, or {@literal null}. */ 127 private ByteVector innerClasses; 128 129 /** The class_index field of the EnclosingMethod attribute, or 0. */ 130 private int enclosingClassIndex; 131 132 /** The method_index field of the EnclosingMethod attribute. */ 133 private int enclosingMethodIndex; 134 135 /** The signature_index field of the Signature attribute, or 0. */ 136 private int signatureIndex; 137 138 /** The source_file_index field of the SourceFile attribute, or 0. */ 139 private int sourceFileIndex; 140 141 /** The debug_extension field of the SourceDebugExtension attribute, or {@literal null}. */ 142 private ByteVector debugExtension; 143 144 /** 145 * The last runtime visible annotation of this class. The previous ones can be accessed with the 146 * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. 147 */ 148 private AnnotationWriter lastRuntimeVisibleAnnotation; 149 150 /** 151 * The last runtime invisible annotation of this class. The previous ones can be accessed with the 152 * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. 153 */ 154 private AnnotationWriter lastRuntimeInvisibleAnnotation; 155 156 /** 157 * The last runtime visible type annotation of this class. The previous ones can be accessed with 158 * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. 159 */ 160 private AnnotationWriter lastRuntimeVisibleTypeAnnotation; 161 162 /** 163 * The last runtime invisible type annotation of this class. The previous ones can be accessed 164 * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. 165 */ 166 private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; 167 168 /** The Module attribute of this class, or {@literal null}. */ 169 private ModuleWriter moduleWriter; 170 171 /** The host_class_index field of the NestHost attribute, or 0. */ 172 private int nestHostClassIndex; 173 174 /** The number_of_classes field of the NestMembers attribute, or 0. */ 175 private int numberOfNestMemberClasses; 176 177 /** The 'classes' array of the NestMembers attribute, or {@literal null}. */ 178 private ByteVector nestMemberClasses; 179 180 /** The number_of_classes field of the PermittedSubtypes attribute, or 0. */ 181 private int numberOfPermittedSubtypeClasses; 182 183 /** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */ 184 private ByteVector permittedSubtypeClasses; 185 186 /** 187 * The record components of this class, stored in a linked list of {@link RecordComponentWriter} 188 * linked via their {@link RecordComponentWriter#delegate} field. This field stores the first 189 * element of this list. 190 */ 191 private RecordComponentWriter firstRecordComponent; 192 193 /** 194 * The record components of this class, stored in a linked list of {@link RecordComponentWriter} 195 * linked via their {@link RecordComponentWriter#delegate} field. This field stores the last 196 * element of this list. 197 */ 198 private RecordComponentWriter lastRecordComponent; 199 200 /** 201 * The first non standard attribute of this class. The next ones can be accessed with the {@link 202 * Attribute#nextAttribute} field. May be {@literal null}. 203 * 204 * <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit. 205 * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link 206 * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the 207 * reverse order specified by the user. 208 */ 209 private Attribute firstAttribute; 210 211 /** 212 * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link 213 * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link 214 * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}. 215 */ 216 private int compute; 217 218 // ----------------------------------------------------------------------------------------------- 219 // Constructor 220 // ----------------------------------------------------------------------------------------------- 221 222 /** 223 * Constructs a new {@link ClassWriter} object. 224 * 225 * @param flags option flags that can be used to modify the default behavior of this class. Must 226 * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. 227 */ 228 public ClassWriter(final int flags) { 229 this(null, flags); 230 } 231 232 /** 233 * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode 234 * transformations. These optimizations are the following: 235 * 236 * <ul> 237 * <li>The constant pool and bootstrap methods from the original class are copied as is in the 238 * new class, which saves time. New constant pool entries and new bootstrap methods will be 239 * added at the end if necessary, but unused constant pool entries or bootstrap methods 240 * <i>won't be removed</i>. 241 * <li>Methods that are not transformed are copied as is in the new class, directly from the 242 * original class bytecode (i.e. without emitting visit events for all the method 243 * instructions), which saves a <i>lot</i> of time. Untransformed methods are detected by 244 * the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come 245 * from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance). 246 * </ul> 247 * 248 * @param classReader the {@link ClassReader} used to read the original class. It will be used to 249 * copy the entire constant pool and bootstrap methods from the original class and also to 250 * copy other fragments of original bytecode where applicable. 251 * @param flags option flags that can be used to modify the default behavior of this class.Must be 252 * zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. <i>These option flags do 253 * not affect methods that are copied as is in the new class. This means that neither the 254 * maximum stack size nor the stack frames will be computed for these methods</i>. 255 */ 256 public ClassWriter(final ClassReader classReader, final int flags) { 257 super(/* latest api = */ Opcodes.ASM7); 258 symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader); 259 if ((flags & COMPUTE_FRAMES) != 0) { 260 this.compute = MethodWriter.COMPUTE_ALL_FRAMES; 261 } else if ((flags & COMPUTE_MAXS) != 0) { 262 this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL; 263 } else { 264 this.compute = MethodWriter.COMPUTE_NOTHING; 265 } 266 } 267 268 // ----------------------------------------------------------------------------------------------- 269 // Implementation of the ClassVisitor abstract class 270 // ----------------------------------------------------------------------------------------------- 271 272 @Override 273 public final void visit( 274 final int version, 275 final int access, 276 final String name, 277 final String signature, 278 final String superName, 279 final String[] interfaces) { 280 this.version = version; 281 this.accessFlags = access; 282 this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name); 283 if (signature != null) { 284 this.signatureIndex = symbolTable.addConstantUtf8(signature); 285 } 286 this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index; 287 if (interfaces != null && interfaces.length > 0) { 288 interfaceCount = interfaces.length; 289 this.interfaces = new int[interfaceCount]; 290 for (int i = 0; i < interfaceCount; ++i) { 291 this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index; 292 } 293 } 294 if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (version & 0xFFFF) >= Opcodes.V1_7) { 295 compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES; 296 } 297 } 298 299 @Override 300 public final void visitSource(final String file, final String debug) { 301 if (file != null) { 302 sourceFileIndex = symbolTable.addConstantUtf8(file); 303 } 304 if (debug != null) { 305 debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE); 306 } 307 } 308 309 @Override 310 public final ModuleVisitor visitModule( 311 final String name, final int access, final String version) { 312 return moduleWriter = 313 new ModuleWriter( 314 symbolTable, 315 symbolTable.addConstantModule(name).index, 316 access, 317 version == null ? 0 : symbolTable.addConstantUtf8(version)); 318 } 319 320 @Override 321 public final void visitNestHost(final String nestHost) { 322 nestHostClassIndex = symbolTable.addConstantClass(nestHost).index; 323 } 324 325 @Override 326 public final void visitOuterClass( 327 final String owner, final String name, final String descriptor) { 328 enclosingClassIndex = symbolTable.addConstantClass(owner).index; 329 if (name != null && descriptor != null) { 330 enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor); 331 } 332 } 333 334 @Override 335 public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 336 if (visible) { 337 return lastRuntimeVisibleAnnotation = 338 AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); 339 } else { 340 return lastRuntimeInvisibleAnnotation = 341 AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); 342 } 343 } 344 345 @Override 346 public final AnnotationVisitor visitTypeAnnotation( 347 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 348 if (visible) { 349 return lastRuntimeVisibleTypeAnnotation = 350 AnnotationWriter.create( 351 symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); 352 } else { 353 return lastRuntimeInvisibleTypeAnnotation = 354 AnnotationWriter.create( 355 symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); 356 } 357 } 358 359 @Override 360 public final void visitAttribute(final Attribute attribute) { 361 // Store the attributes in the <i>reverse</i> order of their visit by this method. 362 attribute.nextAttribute = firstAttribute; 363 firstAttribute = attribute; 364 } 365 366 @Override 367 public final void visitNestMember(final String nestMember) { 368 if (nestMemberClasses == null) { 369 nestMemberClasses = new ByteVector(); 370 } 371 ++numberOfNestMemberClasses; 372 nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index); 373 } 374 375 @Override 376 @SuppressWarnings("deprecation") 377 public final void visitPermittedSubtypeExperimental(final String permittedSubtype) { 378 if (permittedSubtypeClasses == null) { 379 permittedSubtypeClasses = new ByteVector(); 380 } 381 ++numberOfPermittedSubtypeClasses; 382 permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index); 383 } 384 385 @Override 386 public final void visitInnerClass( 387 final String name, final String outerName, final String innerName, final int access) { 388 if (innerClasses == null) { 389 innerClasses = new ByteVector(); 390 } 391 // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table 392 // which represents a class or interface C that is not a package member must have exactly one 393 // corresponding entry in the classes array". To avoid duplicates we keep track in the info 394 // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has 395 // already been added for C. If so, we store the index of this inner class entry (plus one) in 396 // the info field. This trick allows duplicate detection in O(1) time. 397 Symbol nameSymbol = symbolTable.addConstantClass(name); 398 if (nameSymbol.info == 0) { 399 ++numberOfInnerClasses; 400 innerClasses.putShort(nameSymbol.index); 401 innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index); 402 innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName)); 403 innerClasses.putShort(access); 404 nameSymbol.info = numberOfInnerClasses; 405 } 406 // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method 407 // and throw an exception if there is a difference? 408 } 409 410 @Override 411 @SuppressWarnings("deprecation") 412 public final RecordComponentVisitor visitRecordComponentExperimental( 413 final int access, final String name, final String descriptor, final String signature) { 414 RecordComponentWriter recordComponentWriter = 415 new RecordComponentWriter(symbolTable, access, name, descriptor, signature); 416 if (firstRecordComponent == null) { 417 firstRecordComponent = recordComponentWriter; 418 } else { 419 lastRecordComponent.delegate = recordComponentWriter; 420 } 421 return lastRecordComponent = recordComponentWriter; 422 } 423 424 @Override 425 public final FieldVisitor visitField( 426 final int access, 427 final String name, 428 final String descriptor, 429 final String signature, 430 final Object value) { 431 FieldWriter fieldWriter = 432 new FieldWriter(symbolTable, access, name, descriptor, signature, value); 433 if (firstField == null) { 434 firstField = fieldWriter; 435 } else { 436 lastField.fv = fieldWriter; 437 } 438 return lastField = fieldWriter; 439 } 440 441 @Override 442 public final MethodVisitor visitMethod( 443 final int access, 444 final String name, 445 final String descriptor, 446 final String signature, 447 final String[] exceptions) { 448 MethodWriter methodWriter = 449 new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute); 450 if (firstMethod == null) { 451 firstMethod = methodWriter; 452 } else { 453 lastMethod.mv = methodWriter; 454 } 455 return lastMethod = methodWriter; 456 } 457 458 @Override 459 public final void visitEnd() { 460 // Nothing to do. 461 } 462 463 // ----------------------------------------------------------------------------------------------- 464 // Other public methods 465 // ----------------------------------------------------------------------------------------------- 466 467 /** 468 * Returns the content of the class file that was built by this ClassWriter. 469 * 470 * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter. 471 * @throws ClassTooLargeException if the constant pool of the class is too large. 472 * @throws MethodTooLargeException if the Code attribute of a method is too large. 473 */ 474 public byte[] toByteArray() { 475 // First step: compute the size in bytes of the ClassFile structure. 476 // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version, 477 // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, 478 // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too. 479 int size = 24 + 2 * interfaceCount; 480 int fieldsCount = 0; 481 FieldWriter fieldWriter = firstField; 482 while (fieldWriter != null) { 483 ++fieldsCount; 484 size += fieldWriter.computeFieldInfoSize(); 485 fieldWriter = (FieldWriter) fieldWriter.fv; 486 } 487 int methodsCount = 0; 488 MethodWriter methodWriter = firstMethod; 489 while (methodWriter != null) { 490 ++methodsCount; 491 size += methodWriter.computeMethodInfoSize(); 492 methodWriter = (MethodWriter) methodWriter.mv; 493 } 494 495 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. 496 int attributesCount = 0; 497 if (innerClasses != null) { 498 ++attributesCount; 499 size += 8 + innerClasses.length; 500 symbolTable.addConstantUtf8(Constants.INNER_CLASSES); 501 } 502 if (enclosingClassIndex != 0) { 503 ++attributesCount; 504 size += 10; 505 symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD); 506 } 507 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { 508 ++attributesCount; 509 size += 6; 510 symbolTable.addConstantUtf8(Constants.SYNTHETIC); 511 } 512 if (signatureIndex != 0) { 513 ++attributesCount; 514 size += 8; 515 symbolTable.addConstantUtf8(Constants.SIGNATURE); 516 } 517 if (sourceFileIndex != 0) { 518 ++attributesCount; 519 size += 8; 520 symbolTable.addConstantUtf8(Constants.SOURCE_FILE); 521 } 522 if (debugExtension != null) { 523 ++attributesCount; 524 size += 6 + debugExtension.length; 525 symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION); 526 } 527 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { 528 ++attributesCount; 529 size += 6; 530 symbolTable.addConstantUtf8(Constants.DEPRECATED); 531 } 532 if (lastRuntimeVisibleAnnotation != null) { 533 ++attributesCount; 534 size += 535 lastRuntimeVisibleAnnotation.computeAnnotationsSize( 536 Constants.RUNTIME_VISIBLE_ANNOTATIONS); 537 } 538 if (lastRuntimeInvisibleAnnotation != null) { 539 ++attributesCount; 540 size += 541 lastRuntimeInvisibleAnnotation.computeAnnotationsSize( 542 Constants.RUNTIME_INVISIBLE_ANNOTATIONS); 543 } 544 if (lastRuntimeVisibleTypeAnnotation != null) { 545 ++attributesCount; 546 size += 547 lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( 548 Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); 549 } 550 if (lastRuntimeInvisibleTypeAnnotation != null) { 551 ++attributesCount; 552 size += 553 lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( 554 Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); 555 } 556 if (symbolTable.computeBootstrapMethodsSize() > 0) { 557 ++attributesCount; 558 size += symbolTable.computeBootstrapMethodsSize(); 559 } 560 if (moduleWriter != null) { 561 attributesCount += moduleWriter.getAttributeCount(); 562 size += moduleWriter.computeAttributesSize(); 563 } 564 if (nestHostClassIndex != 0) { 565 ++attributesCount; 566 size += 8; 567 symbolTable.addConstantUtf8(Constants.NEST_HOST); 568 } 569 if (nestMemberClasses != null) { 570 ++attributesCount; 571 size += 8 + nestMemberClasses.length; 572 symbolTable.addConstantUtf8(Constants.NEST_MEMBERS); 573 } 574 if (permittedSubtypeClasses != null) { 575 ++attributesCount; 576 size += 8 + permittedSubtypeClasses.length; 577 symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES); 578 } 579 int recordComponentCount = 0; 580 int recordSize = 0; 581 if (firstRecordComponent != null) { 582 RecordComponentWriter recordComponentWriter = firstRecordComponent; 583 while (recordComponentWriter != null) { 584 ++recordComponentCount; 585 recordSize += recordComponentWriter.computeRecordComponentInfoSize(); 586 recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate; 587 } 588 ++attributesCount; 589 size += 8 + recordSize; 590 symbolTable.addConstantUtf8(Constants.RECORD); 591 } 592 if (firstAttribute != null) { 593 attributesCount += firstAttribute.getAttributeCount(); 594 size += firstAttribute.computeAttributesSize(symbolTable); 595 } 596 // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous 597 // statements can add attribute names to the constant pool, thereby changing its size! 598 size += symbolTable.getConstantPoolLength(); 599 int constantPoolCount = symbolTable.getConstantPoolCount(); 600 if (constantPoolCount > 0xFFFF) { 601 throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount); 602 } 603 604 // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in 605 // dynamic resizes) and fill it with the ClassFile content. 606 ByteVector result = new ByteVector(size); 607 result.putInt(0xCAFEBABE).putInt(version); 608 symbolTable.putConstantPool(result); 609 int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0; 610 result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass); 611 result.putShort(interfaceCount); 612 for (int i = 0; i < interfaceCount; ++i) { 613 result.putShort(interfaces[i]); 614 } 615 result.putShort(fieldsCount); 616 fieldWriter = firstField; 617 while (fieldWriter != null) { 618 fieldWriter.putFieldInfo(result); 619 fieldWriter = (FieldWriter) fieldWriter.fv; 620 } 621 result.putShort(methodsCount); 622 boolean hasFrames = false; 623 boolean hasAsmInstructions = false; 624 methodWriter = firstMethod; 625 while (methodWriter != null) { 626 hasFrames |= methodWriter.hasFrames(); 627 hasAsmInstructions |= methodWriter.hasAsmInstructions(); 628 methodWriter.putMethodInfo(result); 629 methodWriter = (MethodWriter) methodWriter.mv; 630 } 631 // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. 632 result.putShort(attributesCount); 633 if (innerClasses != null) { 634 result 635 .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES)) 636 .putInt(innerClasses.length + 2) 637 .putShort(numberOfInnerClasses) 638 .putByteArray(innerClasses.data, 0, innerClasses.length); 639 } 640 if (enclosingClassIndex != 0) { 641 result 642 .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD)) 643 .putInt(4) 644 .putShort(enclosingClassIndex) 645 .putShort(enclosingMethodIndex); 646 } 647 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { 648 result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); 649 } 650 if (signatureIndex != 0) { 651 result 652 .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) 653 .putInt(2) 654 .putShort(signatureIndex); 655 } 656 if (sourceFileIndex != 0) { 657 result 658 .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE)) 659 .putInt(2) 660 .putShort(sourceFileIndex); 661 } 662 if (debugExtension != null) { 663 int length = debugExtension.length; 664 result 665 .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION)) 666 .putInt(length) 667 .putByteArray(debugExtension.data, 0, length); 668 } 669 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { 670 result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); 671 } 672 AnnotationWriter.putAnnotations( 673 symbolTable, 674 lastRuntimeVisibleAnnotation, 675 lastRuntimeInvisibleAnnotation, 676 lastRuntimeVisibleTypeAnnotation, 677 lastRuntimeInvisibleTypeAnnotation, 678 result); 679 symbolTable.putBootstrapMethods(result); 680 if (moduleWriter != null) { 681 moduleWriter.putAttributes(result); 682 } 683 if (nestHostClassIndex != 0) { 684 result 685 .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST)) 686 .putInt(2) 687 .putShort(nestHostClassIndex); 688 } 689 if (nestMemberClasses != null) { 690 result 691 .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS)) 692 .putInt(nestMemberClasses.length + 2) 693 .putShort(numberOfNestMemberClasses) 694 .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length); 695 } 696 if (permittedSubtypeClasses != null) { 697 result 698 .putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES)) 699 .putInt(permittedSubtypeClasses.length + 2) 700 .putShort(numberOfPermittedSubtypeClasses) 701 .putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length); 702 } 703 if (firstRecordComponent != null) { 704 result 705 .putShort(symbolTable.addConstantUtf8(Constants.RECORD)) 706 .putInt(recordSize + 2) 707 .putShort(recordComponentCount); 708 RecordComponentWriter recordComponentWriter = firstRecordComponent; 709 while (recordComponentWriter != null) { 710 recordComponentWriter.putRecordComponentInfo(result); 711 recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate; 712 } 713 } 714 if (firstAttribute != null) { 715 firstAttribute.putAttributes(symbolTable, result); 716 } 717 718 // Third step: replace the ASM specific instructions, if any. 719 if (hasAsmInstructions) { 720 return replaceAsmInstructions(result.data, hasFrames); 721 } else { 722 return result.data; 723 } 724 } 725 726 /** 727 * Returns the equivalent of the given class file, with the ASM specific instructions replaced 728 * with standard ones. This is done with a ClassReader -> ClassWriter round trip. 729 * 730 * @param classFile a class file containing ASM specific instructions, generated by this 731 * ClassWriter. 732 * @param hasFrames whether there is at least one stack map frames in 'classFile'. 733 * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard 734 * ones. 735 */ 736 private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) { 737 final Attribute[] attributes = getAttributePrototypes(); 738 firstField = null; 739 lastField = null; 740 firstMethod = null; 741 lastMethod = null; 742 lastRuntimeVisibleAnnotation = null; 743 lastRuntimeInvisibleAnnotation = null; 744 lastRuntimeVisibleTypeAnnotation = null; 745 lastRuntimeInvisibleTypeAnnotation = null; 746 moduleWriter = null; 747 nestHostClassIndex = 0; 748 numberOfNestMemberClasses = 0; 749 nestMemberClasses = null; 750 numberOfPermittedSubtypeClasses = 0; 751 permittedSubtypeClasses = null; 752 firstRecordComponent = null; 753 lastRecordComponent = null; 754 firstAttribute = null; 755 compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING; 756 new ClassReader(classFile, 0, /* checkClassVersion = */ false) 757 .accept( 758 this, 759 attributes, 760 (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS); 761 return toByteArray(); 762 } 763 764 /** 765 * Returns the prototypes of the attributes used by this class, its fields and its methods. 766 * 767 * @return the prototypes of the attributes used by this class, its fields and its methods. 768 */ 769 private Attribute[] getAttributePrototypes() { 770 Attribute.Set attributePrototypes = new Attribute.Set(); 771 attributePrototypes.addAttributes(firstAttribute); 772 FieldWriter fieldWriter = firstField; 773 while (fieldWriter != null) { 774 fieldWriter.collectAttributePrototypes(attributePrototypes); 775 fieldWriter = (FieldWriter) fieldWriter.fv; 776 } 777 MethodWriter methodWriter = firstMethod; 778 while (methodWriter != null) { 779 methodWriter.collectAttributePrototypes(attributePrototypes); 780 methodWriter = (MethodWriter) methodWriter.mv; 781 } 782 RecordComponentWriter recordComponentWriter = firstRecordComponent; 783 while (recordComponentWriter != null) { 784 recordComponentWriter.collectAttributePrototypes(attributePrototypes); 785 recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate; 786 } 787 return attributePrototypes.toArray(); 788 } 789 790 // ----------------------------------------------------------------------------------------------- 791 // Utility methods: constant pool management for Attribute sub classes 792 // ----------------------------------------------------------------------------------------------- 793 794 /** 795 * Adds a number or string constant to the constant pool of the class being build. Does nothing if 796 * the constant pool already contains a similar item. <i>This method is intended for {@link 797 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 798 * 799 * @param value the value of the constant to be added to the constant pool. This parameter must be 800 * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. 801 * @return the index of a new or already existing constant item with the given value. 802 */ 803 public int newConst(final Object value) { 804 return symbolTable.addConstant(value).index; 805 } 806 807 /** 808 * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant 809 * pool already contains a similar item. <i>This method is intended for {@link Attribute} sub 810 * classes, and is normally not needed by class generators or adapters.</i> 811 * 812 * @param value the String value. 813 * @return the index of a new or already existing UTF8 item. 814 */ 815 // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). 816 public int newUTF8(final String value) { 817 return symbolTable.addConstantUtf8(value); 818 } 819 820 /** 821 * Adds a class reference to the constant pool of the class being build. Does nothing if the 822 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute} 823 * sub classes, and is normally not needed by class generators or adapters.</i> 824 * 825 * @param value the internal name of the class. 826 * @return the index of a new or already existing class reference item. 827 */ 828 public int newClass(final String value) { 829 return symbolTable.addConstantClass(value).index; 830 } 831 832 /** 833 * Adds a method type reference to the constant pool of the class being build. Does nothing if the 834 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute} 835 * sub classes, and is normally not needed by class generators or adapters.</i> 836 * 837 * @param methodDescriptor method descriptor of the method type. 838 * @return the index of a new or already existing method type reference item. 839 */ 840 public int newMethodType(final String methodDescriptor) { 841 return symbolTable.addConstantMethodType(methodDescriptor).index; 842 } 843 844 /** 845 * Adds a module reference to the constant pool of the class being build. Does nothing if the 846 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute} 847 * sub classes, and is normally not needed by class generators or adapters.</i> 848 * 849 * @param moduleName name of the module. 850 * @return the index of a new or already existing module reference item. 851 */ 852 public int newModule(final String moduleName) { 853 return symbolTable.addConstantModule(moduleName).index; 854 } 855 856 /** 857 * Adds a package reference to the constant pool of the class being build. Does nothing if the 858 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute} 859 * sub classes, and is normally not needed by class generators or adapters.</i> 860 * 861 * @param packageName name of the package in its internal form. 862 * @return the index of a new or already existing module reference item. 863 */ 864 public int newPackage(final String packageName) { 865 return symbolTable.addConstantPackage(packageName).index; 866 } 867 868 /** 869 * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool 870 * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes, 871 * and is normally not needed by class generators or adapters.</i> 872 * 873 * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link 874 * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link 875 * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, 876 * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. 877 * @param owner the internal name of the field or method owner class. 878 * @param name the name of the field or method. 879 * @param descriptor the descriptor of the field or method. 880 * @return the index of a new or already existing method type reference item. 881 * @deprecated this method is superseded by {@link #newHandle(int, String, String, String, 882 * boolean)}. 883 */ 884 @Deprecated 885 public int newHandle( 886 final int tag, final String owner, final String name, final String descriptor) { 887 return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); 888 } 889 890 /** 891 * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool 892 * already contains a similar item. <i>This method is intended for {@link Attribute} sub classes, 893 * and is normally not needed by class generators or adapters.</i> 894 * 895 * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link 896 * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link 897 * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, 898 * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. 899 * @param owner the internal name of the field or method owner class. 900 * @param name the name of the field or method. 901 * @param descriptor the descriptor of the field or method. 902 * @param isInterface true if the owner is an interface. 903 * @return the index of a new or already existing method type reference item. 904 */ 905 public int newHandle( 906 final int tag, 907 final String owner, 908 final String name, 909 final String descriptor, 910 final boolean isInterface) { 911 return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index; 912 } 913 914 /** 915 * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing 916 * if the constant pool already contains a similar item. <i>This method is intended for {@link 917 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 918 * 919 * @param name the name of the invoked method. 920 * @param descriptor field descriptor of the constant type. 921 * @param bootstrapMethodHandle the bootstrap method. 922 * @param bootstrapMethodArguments the bootstrap method constant arguments. 923 * @return the index of a new or already existing dynamic constant reference item. 924 */ 925 public int newConstantDynamic( 926 final String name, 927 final String descriptor, 928 final Handle bootstrapMethodHandle, 929 final Object... bootstrapMethodArguments) { 930 return symbolTable.addConstantDynamic( 931 name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) 932 .index; 933 } 934 935 /** 936 * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if 937 * the constant pool already contains a similar item. <i>This method is intended for {@link 938 * Attribute} sub classes, and is normally not needed by class generators or adapters.</i> 939 * 940 * @param name the name of the invoked method. 941 * @param descriptor descriptor of the invoke method. 942 * @param bootstrapMethodHandle the bootstrap method. 943 * @param bootstrapMethodArguments the bootstrap method constant arguments. 944 * @return the index of a new or already existing invokedynamic reference item. 945 */ 946 public int newInvokeDynamic( 947 final String name, 948 final String descriptor, 949 final Handle bootstrapMethodHandle, 950 final Object... bootstrapMethodArguments) { 951 return symbolTable.addConstantInvokeDynamic( 952 name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) 953 .index; 954 } 955 956 /** 957 * Adds a field reference to the constant pool of the class being build. Does nothing if the 958 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute} 959 * sub classes, and is normally not needed by class generators or adapters.</i> 960 * 961 * @param owner the internal name of the field's owner class. 962 * @param name the field's name. 963 * @param descriptor the field's descriptor. 964 * @return the index of a new or already existing field reference item. 965 */ 966 public int newField(final String owner, final String name, final String descriptor) { 967 return symbolTable.addConstantFieldref(owner, name, descriptor).index; 968 } 969 970 /** 971 * Adds a method reference to the constant pool of the class being build. Does nothing if the 972 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute} 973 * sub classes, and is normally not needed by class generators or adapters.</i> 974 * 975 * @param owner the internal name of the method's owner class. 976 * @param name the method's name. 977 * @param descriptor the method's descriptor. 978 * @param isInterface {@literal true} if {@code owner} is an interface. 979 * @return the index of a new or already existing method reference item. 980 */ 981 public int newMethod( 982 final String owner, final String name, final String descriptor, final boolean isInterface) { 983 return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index; 984 } 985 986 /** 987 * Adds a name and type to the constant pool of the class being build. Does nothing if the 988 * constant pool already contains a similar item. <i>This method is intended for {@link Attribute} 989 * sub classes, and is normally not needed by class generators or adapters.</i> 990 * 991 * @param name a name. 992 * @param descriptor a type descriptor. 993 * @return the index of a new or already existing name and type item. 994 */ 995 public int newNameType(final String name, final String descriptor) { 996 return symbolTable.addConstantNameAndType(name, descriptor); 997 } 998 999 // ----------------------------------------------------------------------------------------------- 1000 // Default method to compute common super classes when computing stack map frames 1001 // ----------------------------------------------------------------------------------------------- 1002 1003 /** 1004 * Returns the common super type of the two given types. The default implementation of this method 1005 * <i>loads</i> the two given classes and uses the java.lang.Class methods to find the common 1006 * super class. It can be overridden to compute this common super type in other ways, in 1007 * particular without actually loading any class, or to take into account the class that is 1008 * currently being generated by this ClassWriter, which can of course not be loaded since it is 1009 * under construction. 1010 * 1011 * @param type1 the internal name of a class. 1012 * @param type2 the internal name of another class. 1013 * @return the internal name of the common super class of the two given classes. 1014 */ 1015 protected String getCommonSuperClass(final String type1, final String type2) { 1016 ClassLoader classLoader = getClassLoader(); 1017 Class<?> class1; 1018 try { 1019 class1 = Class.forName(type1.replace('/', '.'), false, classLoader); 1020 } catch (ClassNotFoundException e) { 1021 throw new TypeNotPresentException(type1, e); 1022 } 1023 Class<?> class2; 1024 try { 1025 class2 = Class.forName(type2.replace('/', '.'), false, classLoader); 1026 } catch (ClassNotFoundException e) { 1027 throw new TypeNotPresentException(type2, e); 1028 } 1029 if (class1.isAssignableFrom(class2)) { 1030 return type1; 1031 } 1032 if (class2.isAssignableFrom(class1)) { 1033 return type2; 1034 } 1035 if (class1.isInterface() || class2.isInterface()) { 1036 return "java/lang/Object"; 1037 } else { 1038 do { 1039 class1 = class1.getSuperclass(); 1040 } while (!class1.isAssignableFrom(class2)); 1041 return class1.getName().replace('.', '/'); 1042 } 1043 } 1044 1045 /** 1046 * Returns the {@link ClassLoader} to be used by the default implementation of {@link 1047 * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by 1048 * default. 1049 * 1050 * @return ClassLoader 1051 */ 1052 protected ClassLoader getClassLoader() { 1053 // SPRING PATCH: prefer thread context ClassLoader for application classes 1054 ClassLoader classLoader = null; 1055 try { 1056 classLoader = Thread.currentThread().getContextClassLoader(); 1057 } catch (Throwable ex) { 1058 // Cannot access thread context ClassLoader - falling back... 1059 } 1060 return (classLoader != null ? classLoader : getClass().getClassLoader()); 1061 } 1062}