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