1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.util; 29 30 import java.io.IOException; 31 import java.io.PrintWriter; 32 import java.util.Arrays; 33 import java.util.Collections; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 import org.objectweb.asm.Attribute; 38 import org.objectweb.asm.ConstantDynamic; 39 import org.objectweb.asm.Handle; 40 import org.objectweb.asm.Label; 41 import org.objectweb.asm.Opcodes; 42 import org.objectweb.asm.Type; 43 import org.objectweb.asm.TypePath; 44 45 /** 46 * A {@link Printer} that prints the ASM code to generate the classes it visits. 47 * 48 * @author Eric Bruneton 49 */ 50 // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). 51 public class ASMifier extends Printer { 52 53 /** The help message shown when command line arguments are incorrect. */ 54 private static final String USAGE = 55 "Prints the ASM code to generate the given class.\n" 56 + "Usage: ASMifier [-nodebug] <fully qualified class name or class file name>"; 57 58 /** A pseudo access flag used to distinguish class access flags. */ 59 private static final int ACCESS_CLASS = 0x40000; 60 61 /** A pseudo access flag used to distinguish field access flags. */ 62 private static final int ACCESS_FIELD = 0x80000; 63 64 /** A pseudo access flag used to distinguish inner class flags. */ 65 private static final int ACCESS_INNER = 0x100000; 66 67 /** A pseudo access flag used to distinguish module requires / exports flags. */ 68 private static final int ACCESS_MODULE = 0x200000; 69 70 private static final String ANNOTATION_VISITOR = "annotationVisitor"; 71 private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = "; 72 private static final String COMMA = "\", \""; 73 private static final String END_ARRAY = " });\n"; 74 private static final String END_PARAMETERS = ");\n\n"; 75 private static final String NEW_OBJECT_ARRAY = ", new Object[] {"; 76 private static final String VISIT_END = ".visitEnd();\n"; 77 78 private static final List<String> FRAME_TYPES = 79 Collections.unmodifiableList( 80 Arrays.asList( 81 "Opcodes.TOP", 82 "Opcodes.INTEGER", 83 "Opcodes.FLOAT", 84 "Opcodes.DOUBLE", 85 "Opcodes.LONG", 86 "Opcodes.NULL", 87 "Opcodes.UNINITIALIZED_THIS")); 88 89 private static final Map<Integer, String> CLASS_VERSIONS; 90 91 static { 92 HashMap<Integer, String> classVersions = new HashMap<>(); classVersions.put(Opcodes.V1_1, "V1_1")93 classVersions.put(Opcodes.V1_1, "V1_1"); classVersions.put(Opcodes.V1_2, "V1_2")94 classVersions.put(Opcodes.V1_2, "V1_2"); classVersions.put(Opcodes.V1_3, "V1_3")95 classVersions.put(Opcodes.V1_3, "V1_3"); classVersions.put(Opcodes.V1_4, "V1_4")96 classVersions.put(Opcodes.V1_4, "V1_4"); classVersions.put(Opcodes.V1_5, "V1_5")97 classVersions.put(Opcodes.V1_5, "V1_5"); classVersions.put(Opcodes.V1_6, "V1_6")98 classVersions.put(Opcodes.V1_6, "V1_6"); classVersions.put(Opcodes.V1_7, "V1_7")99 classVersions.put(Opcodes.V1_7, "V1_7"); classVersions.put(Opcodes.V1_8, "V1_8")100 classVersions.put(Opcodes.V1_8, "V1_8"); classVersions.put(Opcodes.V9, "V9")101 classVersions.put(Opcodes.V9, "V9"); classVersions.put(Opcodes.V10, "V10")102 classVersions.put(Opcodes.V10, "V10"); classVersions.put(Opcodes.V11, "V11")103 classVersions.put(Opcodes.V11, "V11"); classVersions.put(Opcodes.V12, "V12")104 classVersions.put(Opcodes.V12, "V12"); classVersions.put(Opcodes.V13, "V13")105 classVersions.put(Opcodes.V13, "V13"); classVersions.put(Opcodes.V14, "V14")106 classVersions.put(Opcodes.V14, "V14"); classVersions.put(Opcodes.V15, "V15")107 classVersions.put(Opcodes.V15, "V15"); classVersions.put(Opcodes.V16, "V16")108 classVersions.put(Opcodes.V16, "V16"); classVersions.put(Opcodes.V17, "V17")109 classVersions.put(Opcodes.V17, "V17"); classVersions.put(Opcodes.V18, "V18")110 classVersions.put(Opcodes.V18, "V18"); classVersions.put(Opcodes.V19, "V19")111 classVersions.put(Opcodes.V19, "V19"); classVersions.put(Opcodes.V20, "V20")112 classVersions.put(Opcodes.V20, "V20"); classVersions.put(Opcodes.V21, "V21")113 classVersions.put(Opcodes.V21, "V21"); 114 CLASS_VERSIONS = Collections.unmodifiableMap(classVersions); 115 } 116 117 /** The name of the visitor variable in the produced code. */ 118 protected final String name; 119 120 /** The identifier of the annotation visitor variable in the produced code. */ 121 protected final int id; 122 123 /** The name of the Label variables in the produced code. */ 124 protected Map<Label, String> labelNames; 125 126 /** 127 * Constructs a new {@link ASMifier}. <i>Subclasses must not use this constructor</i>. Instead, 128 * they must use the {@link #ASMifier(int, String, int)} version. 129 * 130 * @throws IllegalStateException If a subclass calls this constructor. 131 */ ASMifier()132 public ASMifier() { 133 this(/* latest api = */ Opcodes.ASM9, "classWriter", 0); 134 if (getClass() != ASMifier.class) { 135 throw new IllegalStateException(); 136 } 137 } 138 139 /** 140 * Constructs a new {@link ASMifier}. 141 * 142 * @param api the ASM API version implemented by this class. Must be one of the {@code 143 * ASM}<i>x</i> values in {@link Opcodes}. 144 * @param visitorVariableName the name of the visitor variable in the produced code. 145 * @param annotationVisitorId identifier of the annotation visitor variable in the produced code. 146 */ ASMifier( final int api, final String visitorVariableName, final int annotationVisitorId)147 protected ASMifier( 148 final int api, final String visitorVariableName, final int annotationVisitorId) { 149 super(api); 150 this.name = visitorVariableName; 151 this.id = annotationVisitorId; 152 } 153 154 /** 155 * Prints the ASM source code to generate the given class to the standard output. 156 * 157 * <p>Usage: ASMifier [-nodebug] <binary class name or class file name> 158 * 159 * @param args the command line arguments. 160 * @throws IOException if the class cannot be found, or if an IOException occurs. 161 */ main(final String[] args)162 public static void main(final String[] args) throws IOException { 163 main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true)); 164 } 165 166 /** 167 * Prints the ASM source code to generate the given class to the given output. 168 * 169 * <p>Usage: ASMifier [-nodebug] <binary class name or class file name> 170 * 171 * @param args the command line arguments. 172 * @param output where to print the result. 173 * @param logger where to log errors. 174 * @throws IOException if the class cannot be found, or if an IOException occurs. 175 */ main(final String[] args, final PrintWriter output, final PrintWriter logger)176 static void main(final String[] args, final PrintWriter output, final PrintWriter logger) 177 throws IOException { 178 main(args, USAGE, new ASMifier(), output, logger); 179 } 180 181 // ----------------------------------------------------------------------------------------------- 182 // Classes 183 // ----------------------------------------------------------------------------------------------- 184 185 @Override visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)186 public void visit( 187 final int version, 188 final int access, 189 final String name, 190 final String signature, 191 final String superName, 192 final String[] interfaces) { 193 String simpleName; 194 if (name == null) { 195 simpleName = "module-info"; 196 } else { 197 int lastSlashIndex = name.lastIndexOf('/'); 198 if (lastSlashIndex == -1) { 199 simpleName = name; 200 } else { 201 text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n"); 202 simpleName = name.substring(lastSlashIndex + 1).replaceAll("[-\\(\\)]", "_"); 203 } 204 } 205 text.add("import org.objectweb.asm.AnnotationVisitor;\n"); 206 text.add("import org.objectweb.asm.Attribute;\n"); 207 text.add("import org.objectweb.asm.ClassReader;\n"); 208 text.add("import org.objectweb.asm.ClassWriter;\n"); 209 text.add("import org.objectweb.asm.ConstantDynamic;\n"); 210 text.add("import org.objectweb.asm.FieldVisitor;\n"); 211 text.add("import org.objectweb.asm.Handle;\n"); 212 text.add("import org.objectweb.asm.Label;\n"); 213 text.add("import org.objectweb.asm.MethodVisitor;\n"); 214 text.add("import org.objectweb.asm.Opcodes;\n"); 215 text.add("import org.objectweb.asm.RecordComponentVisitor;\n"); 216 text.add("import org.objectweb.asm.Type;\n"); 217 text.add("import org.objectweb.asm.TypePath;\n"); 218 text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); 219 text.add("public static byte[] dump () throws Exception {\n\n"); 220 text.add("ClassWriter classWriter = new ClassWriter(0);\n"); 221 text.add("FieldVisitor fieldVisitor;\n"); 222 text.add("RecordComponentVisitor recordComponentVisitor;\n"); 223 text.add("MethodVisitor methodVisitor;\n"); 224 text.add("AnnotationVisitor annotationVisitor0;\n\n"); 225 226 stringBuilder.setLength(0); 227 stringBuilder.append("classWriter.visit("); 228 String versionString = CLASS_VERSIONS.get(version); 229 if (versionString != null) { 230 stringBuilder.append(versionString); 231 } else { 232 stringBuilder.append(version); 233 } 234 stringBuilder.append(", "); 235 appendAccessFlags(access | ACCESS_CLASS); 236 stringBuilder.append(", "); 237 appendConstant(name); 238 stringBuilder.append(", "); 239 appendConstant(signature); 240 stringBuilder.append(", "); 241 appendConstant(superName); 242 stringBuilder.append(", "); 243 if (interfaces != null && interfaces.length > 0) { 244 stringBuilder.append("new String[] {"); 245 for (int i = 0; i < interfaces.length; ++i) { 246 stringBuilder.append(i == 0 ? " " : ", "); 247 appendConstant(interfaces[i]); 248 } 249 stringBuilder.append(" }"); 250 } else { 251 stringBuilder.append("null"); 252 } 253 stringBuilder.append(END_PARAMETERS); 254 text.add(stringBuilder.toString()); 255 } 256 257 @Override visitSource(final String file, final String debug)258 public void visitSource(final String file, final String debug) { 259 stringBuilder.setLength(0); 260 stringBuilder.append("classWriter.visitSource("); 261 appendConstant(file); 262 stringBuilder.append(", "); 263 appendConstant(debug); 264 stringBuilder.append(END_PARAMETERS); 265 text.add(stringBuilder.toString()); 266 } 267 268 @Override visitModule(final String name, final int flags, final String version)269 public Printer visitModule(final String name, final int flags, final String version) { 270 stringBuilder.setLength(0); 271 stringBuilder.append("{\n"); 272 stringBuilder.append("ModuleVisitor moduleVisitor = classWriter.visitModule("); 273 appendConstant(name); 274 stringBuilder.append(", "); 275 appendAccessFlags(flags | ACCESS_MODULE); 276 stringBuilder.append(", "); 277 appendConstant(version); 278 stringBuilder.append(END_PARAMETERS); 279 text.add(stringBuilder.toString()); 280 ASMifier asmifier = createASMifier("moduleVisitor", 0); 281 text.add(asmifier.getText()); 282 text.add("}\n"); 283 return asmifier; 284 } 285 286 @Override visitNestHost(final String nestHost)287 public void visitNestHost(final String nestHost) { 288 stringBuilder.setLength(0); 289 stringBuilder.append("classWriter.visitNestHost("); 290 appendConstant(nestHost); 291 stringBuilder.append(END_PARAMETERS); 292 text.add(stringBuilder.toString()); 293 } 294 295 @Override visitOuterClass(final String owner, final String name, final String descriptor)296 public void visitOuterClass(final String owner, final String name, final String descriptor) { 297 stringBuilder.setLength(0); 298 stringBuilder.append("classWriter.visitOuterClass("); 299 appendConstant(owner); 300 stringBuilder.append(", "); 301 appendConstant(name); 302 stringBuilder.append(", "); 303 appendConstant(descriptor); 304 stringBuilder.append(END_PARAMETERS); 305 text.add(stringBuilder.toString()); 306 } 307 308 @Override visitClassAnnotation(final String descriptor, final boolean visible)309 public ASMifier visitClassAnnotation(final String descriptor, final boolean visible) { 310 return visitAnnotation(descriptor, visible); 311 } 312 313 @Override visitClassTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)314 public ASMifier visitClassTypeAnnotation( 315 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 316 return visitTypeAnnotation(typeRef, typePath, descriptor, visible); 317 } 318 319 @Override visitClassAttribute(final Attribute attribute)320 public void visitClassAttribute(final Attribute attribute) { 321 visitAttribute(attribute); 322 } 323 324 @Override visitNestMember(final String nestMember)325 public void visitNestMember(final String nestMember) { 326 stringBuilder.setLength(0); 327 stringBuilder.append("classWriter.visitNestMember("); 328 appendConstant(nestMember); 329 stringBuilder.append(END_PARAMETERS); 330 text.add(stringBuilder.toString()); 331 } 332 333 @Override visitPermittedSubclass(final String permittedSubclass)334 public void visitPermittedSubclass(final String permittedSubclass) { 335 stringBuilder.setLength(0); 336 stringBuilder.append("classWriter.visitPermittedSubclass("); 337 appendConstant(permittedSubclass); 338 stringBuilder.append(END_PARAMETERS); 339 text.add(stringBuilder.toString()); 340 } 341 342 @Override visitInnerClass( final String name, final String outerName, final String innerName, final int access)343 public void visitInnerClass( 344 final String name, final String outerName, final String innerName, final int access) { 345 stringBuilder.setLength(0); 346 stringBuilder.append("classWriter.visitInnerClass("); 347 appendConstant(name); 348 stringBuilder.append(", "); 349 appendConstant(outerName); 350 stringBuilder.append(", "); 351 appendConstant(innerName); 352 stringBuilder.append(", "); 353 appendAccessFlags(access | ACCESS_INNER); 354 stringBuilder.append(END_PARAMETERS); 355 text.add(stringBuilder.toString()); 356 } 357 358 @Override visitRecordComponent( final String name, final String descriptor, final String signature)359 public ASMifier visitRecordComponent( 360 final String name, final String descriptor, final String signature) { 361 stringBuilder.setLength(0); 362 stringBuilder.append("{\n"); 363 stringBuilder.append("recordComponentVisitor = classWriter.visitRecordComponent("); 364 appendConstant(name); 365 stringBuilder.append(", "); 366 appendConstant(descriptor); 367 stringBuilder.append(", "); 368 appendConstant(signature); 369 stringBuilder.append(");\n"); 370 text.add(stringBuilder.toString()); 371 ASMifier asmifier = createASMifier("recordComponentVisitor", 0); 372 text.add(asmifier.getText()); 373 text.add("}\n"); 374 return asmifier; 375 } 376 377 @Override visitField( final int access, final String name, final String descriptor, final String signature, final Object value)378 public ASMifier visitField( 379 final int access, 380 final String name, 381 final String descriptor, 382 final String signature, 383 final Object value) { 384 stringBuilder.setLength(0); 385 stringBuilder.append("{\n"); 386 stringBuilder.append("fieldVisitor = classWriter.visitField("); 387 appendAccessFlags(access | ACCESS_FIELD); 388 stringBuilder.append(", "); 389 appendConstant(name); 390 stringBuilder.append(", "); 391 appendConstant(descriptor); 392 stringBuilder.append(", "); 393 appendConstant(signature); 394 stringBuilder.append(", "); 395 appendConstant(value); 396 stringBuilder.append(");\n"); 397 text.add(stringBuilder.toString()); 398 ASMifier asmifier = createASMifier("fieldVisitor", 0); 399 text.add(asmifier.getText()); 400 text.add("}\n"); 401 return asmifier; 402 } 403 404 @Override visitMethod( final int access, final String name, final String descriptor, final String signature, final String[] exceptions)405 public ASMifier visitMethod( 406 final int access, 407 final String name, 408 final String descriptor, 409 final String signature, 410 final String[] exceptions) { 411 stringBuilder.setLength(0); 412 stringBuilder.append("{\n"); 413 stringBuilder.append("methodVisitor = classWriter.visitMethod("); 414 appendAccessFlags(access); 415 stringBuilder.append(", "); 416 appendConstant(name); 417 stringBuilder.append(", "); 418 appendConstant(descriptor); 419 stringBuilder.append(", "); 420 appendConstant(signature); 421 stringBuilder.append(", "); 422 if (exceptions != null && exceptions.length > 0) { 423 stringBuilder.append("new String[] {"); 424 for (int i = 0; i < exceptions.length; ++i) { 425 stringBuilder.append(i == 0 ? " " : ", "); 426 appendConstant(exceptions[i]); 427 } 428 stringBuilder.append(" }"); 429 } else { 430 stringBuilder.append("null"); 431 } 432 stringBuilder.append(");\n"); 433 text.add(stringBuilder.toString()); 434 ASMifier asmifier = createASMifier("methodVisitor", 0); 435 text.add(asmifier.getText()); 436 text.add("}\n"); 437 return asmifier; 438 } 439 440 @Override visitClassEnd()441 public void visitClassEnd() { 442 text.add("classWriter.visitEnd();\n\n"); 443 text.add("return classWriter.toByteArray();\n"); 444 text.add("}\n"); 445 text.add("}\n"); 446 } 447 448 // ----------------------------------------------------------------------------------------------- 449 // Modules 450 // ----------------------------------------------------------------------------------------------- 451 452 @Override visitMainClass(final String mainClass)453 public void visitMainClass(final String mainClass) { 454 stringBuilder.setLength(0); 455 stringBuilder.append("moduleVisitor.visitMainClass("); 456 appendConstant(mainClass); 457 stringBuilder.append(");\n"); 458 text.add(stringBuilder.toString()); 459 } 460 461 @Override visitPackage(final String packaze)462 public void visitPackage(final String packaze) { 463 stringBuilder.setLength(0); 464 stringBuilder.append("moduleVisitor.visitPackage("); 465 appendConstant(packaze); 466 stringBuilder.append(");\n"); 467 text.add(stringBuilder.toString()); 468 } 469 470 @Override visitRequire(final String module, final int access, final String version)471 public void visitRequire(final String module, final int access, final String version) { 472 stringBuilder.setLength(0); 473 stringBuilder.append("moduleVisitor.visitRequire("); 474 appendConstant(module); 475 stringBuilder.append(", "); 476 appendAccessFlags(access | ACCESS_MODULE); 477 stringBuilder.append(", "); 478 appendConstant(version); 479 stringBuilder.append(");\n"); 480 text.add(stringBuilder.toString()); 481 } 482 483 @Override visitExport(final String packaze, final int access, final String... modules)484 public void visitExport(final String packaze, final int access, final String... modules) { 485 visitExportOrOpen("moduleVisitor.visitExport(", packaze, access, modules); 486 } 487 488 @Override visitOpen(final String packaze, final int access, final String... modules)489 public void visitOpen(final String packaze, final int access, final String... modules) { 490 visitExportOrOpen("moduleVisitor.visitOpen(", packaze, access, modules); 491 } 492 visitExportOrOpen( final String visitMethod, final String packaze, final int access, final String... modules)493 private void visitExportOrOpen( 494 final String visitMethod, final String packaze, final int access, final String... modules) { 495 stringBuilder.setLength(0); 496 stringBuilder.append(visitMethod); 497 appendConstant(packaze); 498 stringBuilder.append(", "); 499 appendAccessFlags(access | ACCESS_MODULE); 500 if (modules != null && modules.length > 0) { 501 stringBuilder.append(", new String[] {"); 502 for (int i = 0; i < modules.length; ++i) { 503 stringBuilder.append(i == 0 ? " " : ", "); 504 appendConstant(modules[i]); 505 } 506 stringBuilder.append(" }"); 507 } 508 stringBuilder.append(");\n"); 509 text.add(stringBuilder.toString()); 510 } 511 512 @Override visitUse(final String service)513 public void visitUse(final String service) { 514 stringBuilder.setLength(0); 515 stringBuilder.append("moduleVisitor.visitUse("); 516 appendConstant(service); 517 stringBuilder.append(");\n"); 518 text.add(stringBuilder.toString()); 519 } 520 521 @Override visitProvide(final String service, final String... providers)522 public void visitProvide(final String service, final String... providers) { 523 stringBuilder.setLength(0); 524 stringBuilder.append("moduleVisitor.visitProvide("); 525 appendConstant(service); 526 stringBuilder.append(", new String[] {"); 527 for (int i = 0; i < providers.length; ++i) { 528 stringBuilder.append(i == 0 ? " " : ", "); 529 appendConstant(providers[i]); 530 } 531 stringBuilder.append(END_ARRAY); 532 text.add(stringBuilder.toString()); 533 } 534 535 @Override visitModuleEnd()536 public void visitModuleEnd() { 537 text.add("moduleVisitor.visitEnd();\n"); 538 } 539 540 // ----------------------------------------------------------------------------------------------- 541 // Annotations 542 // ----------------------------------------------------------------------------------------------- 543 544 // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different. 545 @Override visit(final String name, final Object value)546 public void visit(final String name, final Object value) { 547 stringBuilder.setLength(0); 548 stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visit("); 549 appendConstant(name); 550 stringBuilder.append(", "); 551 appendConstant(value); 552 stringBuilder.append(");\n"); 553 text.add(stringBuilder.toString()); 554 } 555 556 @Override visitEnum(final String name, final String descriptor, final String value)557 public void visitEnum(final String name, final String descriptor, final String value) { 558 stringBuilder.setLength(0); 559 stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visitEnum("); 560 appendConstant(name); 561 stringBuilder.append(", "); 562 appendConstant(descriptor); 563 stringBuilder.append(", "); 564 appendConstant(value); 565 stringBuilder.append(");\n"); 566 text.add(stringBuilder.toString()); 567 } 568 569 @Override visitAnnotation(final String name, final String descriptor)570 public ASMifier visitAnnotation(final String name, final String descriptor) { 571 stringBuilder.setLength(0); 572 stringBuilder 573 .append("{\n") 574 .append("AnnotationVisitor annotationVisitor") 575 .append(id + 1) 576 .append(" = annotationVisitor"); 577 stringBuilder.append(id).append(".visitAnnotation("); 578 appendConstant(name); 579 stringBuilder.append(", "); 580 appendConstant(descriptor); 581 stringBuilder.append(");\n"); 582 text.add(stringBuilder.toString()); 583 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1); 584 text.add(asmifier.getText()); 585 text.add("}\n"); 586 return asmifier; 587 } 588 589 @Override visitArray(final String name)590 public ASMifier visitArray(final String name) { 591 stringBuilder.setLength(0); 592 stringBuilder.append("{\n"); 593 stringBuilder 594 .append("AnnotationVisitor annotationVisitor") 595 .append(id + 1) 596 .append(" = annotationVisitor"); 597 stringBuilder.append(id).append(".visitArray("); 598 appendConstant(name); 599 stringBuilder.append(");\n"); 600 text.add(stringBuilder.toString()); 601 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1); 602 text.add(asmifier.getText()); 603 text.add("}\n"); 604 return asmifier; 605 } 606 607 @Override visitAnnotationEnd()608 public void visitAnnotationEnd() { 609 stringBuilder.setLength(0); 610 stringBuilder.append(ANNOTATION_VISITOR).append(id).append(VISIT_END); 611 text.add(stringBuilder.toString()); 612 } 613 614 // ----------------------------------------------------------------------------------------------- 615 // Record components 616 // ----------------------------------------------------------------------------------------------- 617 618 @Override visitRecordComponentAnnotation(final String descriptor, final boolean visible)619 public ASMifier visitRecordComponentAnnotation(final String descriptor, final boolean visible) { 620 return visitAnnotation(descriptor, visible); 621 } 622 623 @Override visitRecordComponentTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)624 public ASMifier visitRecordComponentTypeAnnotation( 625 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 626 return visitTypeAnnotation(typeRef, typePath, descriptor, visible); 627 } 628 629 @Override visitRecordComponentAttribute(final Attribute attribute)630 public void visitRecordComponentAttribute(final Attribute attribute) { 631 visitAttribute(attribute); 632 } 633 634 @Override visitRecordComponentEnd()635 public void visitRecordComponentEnd() { 636 visitMemberEnd(); 637 } 638 639 // ----------------------------------------------------------------------------------------------- 640 // Fields 641 // ----------------------------------------------------------------------------------------------- 642 643 @Override visitFieldAnnotation(final String descriptor, final boolean visible)644 public ASMifier visitFieldAnnotation(final String descriptor, final boolean visible) { 645 return visitAnnotation(descriptor, visible); 646 } 647 648 @Override visitFieldTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)649 public ASMifier visitFieldTypeAnnotation( 650 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 651 return visitTypeAnnotation(typeRef, typePath, descriptor, visible); 652 } 653 654 @Override visitFieldAttribute(final Attribute attribute)655 public void visitFieldAttribute(final Attribute attribute) { 656 visitAttribute(attribute); 657 } 658 659 @Override visitFieldEnd()660 public void visitFieldEnd() { 661 visitMemberEnd(); 662 } 663 664 // ----------------------------------------------------------------------------------------------- 665 // Methods 666 // ----------------------------------------------------------------------------------------------- 667 668 @Override visitParameter(final String parameterName, final int access)669 public void visitParameter(final String parameterName, final int access) { 670 stringBuilder.setLength(0); 671 stringBuilder.append(name).append(".visitParameter("); 672 appendString(stringBuilder, parameterName); 673 stringBuilder.append(", "); 674 appendAccessFlags(access); 675 text.add(stringBuilder.append(");\n").toString()); 676 } 677 678 @Override visitAnnotationDefault()679 public ASMifier visitAnnotationDefault() { 680 stringBuilder.setLength(0); 681 stringBuilder 682 .append("{\n") 683 .append(ANNOTATION_VISITOR0) 684 .append(name) 685 .append(".visitAnnotationDefault();\n"); 686 text.add(stringBuilder.toString()); 687 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0); 688 text.add(asmifier.getText()); 689 text.add("}\n"); 690 return asmifier; 691 } 692 693 @Override visitMethodAnnotation(final String descriptor, final boolean visible)694 public ASMifier visitMethodAnnotation(final String descriptor, final boolean visible) { 695 return visitAnnotation(descriptor, visible); 696 } 697 698 @Override visitMethodTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)699 public ASMifier visitMethodTypeAnnotation( 700 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 701 return visitTypeAnnotation(typeRef, typePath, descriptor, visible); 702 } 703 704 @Override visitAnnotableParameterCount(final int parameterCount, final boolean visible)705 public ASMifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) { 706 stringBuilder.setLength(0); 707 stringBuilder 708 .append(name) 709 .append(".visitAnnotableParameterCount(") 710 .append(parameterCount) 711 .append(", ") 712 .append(visible) 713 .append(");\n"); 714 text.add(stringBuilder.toString()); 715 return this; 716 } 717 718 @Override visitParameterAnnotation( final int parameter, final String descriptor, final boolean visible)719 public ASMifier visitParameterAnnotation( 720 final int parameter, final String descriptor, final boolean visible) { 721 stringBuilder.setLength(0); 722 stringBuilder 723 .append("{\n") 724 .append(ANNOTATION_VISITOR0) 725 .append(name) 726 .append(".visitParameterAnnotation(") 727 .append(parameter) 728 .append(", "); 729 appendConstant(descriptor); 730 stringBuilder.append(", ").append(visible).append(");\n"); 731 text.add(stringBuilder.toString()); 732 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0); 733 text.add(asmifier.getText()); 734 text.add("}\n"); 735 return asmifier; 736 } 737 738 @Override visitMethodAttribute(final Attribute attribute)739 public void visitMethodAttribute(final Attribute attribute) { 740 visitAttribute(attribute); 741 } 742 743 @Override visitCode()744 public void visitCode() { 745 text.add(name + ".visitCode();\n"); 746 } 747 748 @Override visitFrame( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)749 public void visitFrame( 750 final int type, 751 final int numLocal, 752 final Object[] local, 753 final int numStack, 754 final Object[] stack) { 755 stringBuilder.setLength(0); 756 switch (type) { 757 case Opcodes.F_NEW: 758 case Opcodes.F_FULL: 759 declareFrameTypes(numLocal, local); 760 declareFrameTypes(numStack, stack); 761 if (type == Opcodes.F_NEW) { 762 stringBuilder.append(name).append(".visitFrame(Opcodes.F_NEW, "); 763 } else { 764 stringBuilder.append(name).append(".visitFrame(Opcodes.F_FULL, "); 765 } 766 stringBuilder.append(numLocal).append(NEW_OBJECT_ARRAY); 767 appendFrameTypes(numLocal, local); 768 stringBuilder.append("}, ").append(numStack).append(NEW_OBJECT_ARRAY); 769 appendFrameTypes(numStack, stack); 770 stringBuilder.append('}'); 771 break; 772 case Opcodes.F_APPEND: 773 declareFrameTypes(numLocal, local); 774 stringBuilder 775 .append(name) 776 .append(".visitFrame(Opcodes.F_APPEND,") 777 .append(numLocal) 778 .append(NEW_OBJECT_ARRAY); 779 appendFrameTypes(numLocal, local); 780 stringBuilder.append("}, 0, null"); 781 break; 782 case Opcodes.F_CHOP: 783 stringBuilder 784 .append(name) 785 .append(".visitFrame(Opcodes.F_CHOP,") 786 .append(numLocal) 787 .append(", null, 0, null"); 788 break; 789 case Opcodes.F_SAME: 790 stringBuilder.append(name).append(".visitFrame(Opcodes.F_SAME, 0, null, 0, null"); 791 break; 792 case Opcodes.F_SAME1: 793 declareFrameTypes(1, stack); 794 stringBuilder 795 .append(name) 796 .append(".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); 797 appendFrameTypes(1, stack); 798 stringBuilder.append('}'); 799 break; 800 default: 801 throw new IllegalArgumentException(); 802 } 803 stringBuilder.append(");\n"); 804 text.add(stringBuilder.toString()); 805 } 806 807 @Override visitInsn(final int opcode)808 public void visitInsn(final int opcode) { 809 stringBuilder.setLength(0); 810 stringBuilder.append(name).append(".visitInsn(").append(OPCODES[opcode]).append(");\n"); 811 text.add(stringBuilder.toString()); 812 } 813 814 @Override visitIntInsn(final int opcode, final int operand)815 public void visitIntInsn(final int opcode, final int operand) { 816 stringBuilder.setLength(0); 817 stringBuilder 818 .append(name) 819 .append(".visitIntInsn(") 820 .append(OPCODES[opcode]) 821 .append(", ") 822 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand)) 823 .append(");\n"); 824 text.add(stringBuilder.toString()); 825 } 826 827 @Override visitVarInsn(final int opcode, final int varIndex)828 public void visitVarInsn(final int opcode, final int varIndex) { 829 stringBuilder.setLength(0); 830 stringBuilder 831 .append(name) 832 .append(".visitVarInsn(") 833 .append(OPCODES[opcode]) 834 .append(", ") 835 .append(varIndex) 836 .append(");\n"); 837 text.add(stringBuilder.toString()); 838 } 839 840 @Override visitTypeInsn(final int opcode, final String type)841 public void visitTypeInsn(final int opcode, final String type) { 842 stringBuilder.setLength(0); 843 stringBuilder.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]).append(", "); 844 appendConstant(type); 845 stringBuilder.append(");\n"); 846 text.add(stringBuilder.toString()); 847 } 848 849 @Override visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)850 public void visitFieldInsn( 851 final int opcode, final String owner, final String name, final String descriptor) { 852 stringBuilder.setLength(0); 853 stringBuilder.append(this.name).append(".visitFieldInsn(").append(OPCODES[opcode]).append(", "); 854 appendConstant(owner); 855 stringBuilder.append(", "); 856 appendConstant(name); 857 stringBuilder.append(", "); 858 appendConstant(descriptor); 859 stringBuilder.append(");\n"); 860 text.add(stringBuilder.toString()); 861 } 862 863 @Override visitMethodInsn( final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface)864 public void visitMethodInsn( 865 final int opcode, 866 final String owner, 867 final String name, 868 final String descriptor, 869 final boolean isInterface) { 870 stringBuilder.setLength(0); 871 stringBuilder 872 .append(this.name) 873 .append(".visitMethodInsn(") 874 .append(OPCODES[opcode]) 875 .append(", "); 876 appendConstant(owner); 877 stringBuilder.append(", "); 878 appendConstant(name); 879 stringBuilder.append(", "); 880 appendConstant(descriptor); 881 stringBuilder.append(", "); 882 stringBuilder.append(isInterface ? "true" : "false"); 883 stringBuilder.append(");\n"); 884 text.add(stringBuilder.toString()); 885 } 886 887 @Override visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)888 public void visitInvokeDynamicInsn( 889 final String name, 890 final String descriptor, 891 final Handle bootstrapMethodHandle, 892 final Object... bootstrapMethodArguments) { 893 stringBuilder.setLength(0); 894 stringBuilder.append(this.name).append(".visitInvokeDynamicInsn("); 895 appendConstant(name); 896 stringBuilder.append(", "); 897 appendConstant(descriptor); 898 stringBuilder.append(", "); 899 appendConstant(bootstrapMethodHandle); 900 stringBuilder.append(", new Object[]{"); 901 for (int i = 0; i < bootstrapMethodArguments.length; ++i) { 902 appendConstant(bootstrapMethodArguments[i]); 903 if (i != bootstrapMethodArguments.length - 1) { 904 stringBuilder.append(", "); 905 } 906 } 907 stringBuilder.append("});\n"); 908 text.add(stringBuilder.toString()); 909 } 910 911 @Override visitJumpInsn(final int opcode, final Label label)912 public void visitJumpInsn(final int opcode, final Label label) { 913 stringBuilder.setLength(0); 914 declareLabel(label); 915 stringBuilder.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]).append(", "); 916 appendLabel(label); 917 stringBuilder.append(");\n"); 918 text.add(stringBuilder.toString()); 919 } 920 921 @Override visitLabel(final Label label)922 public void visitLabel(final Label label) { 923 stringBuilder.setLength(0); 924 declareLabel(label); 925 stringBuilder.append(name).append(".visitLabel("); 926 appendLabel(label); 927 stringBuilder.append(");\n"); 928 text.add(stringBuilder.toString()); 929 } 930 931 @Override visitLdcInsn(final Object value)932 public void visitLdcInsn(final Object value) { 933 stringBuilder.setLength(0); 934 stringBuilder.append(name).append(".visitLdcInsn("); 935 appendConstant(value); 936 stringBuilder.append(");\n"); 937 text.add(stringBuilder.toString()); 938 } 939 940 @Override visitIincInsn(final int varIndex, final int increment)941 public void visitIincInsn(final int varIndex, final int increment) { 942 stringBuilder.setLength(0); 943 stringBuilder 944 .append(name) 945 .append(".visitIincInsn(") 946 .append(varIndex) 947 .append(", ") 948 .append(increment) 949 .append(");\n"); 950 text.add(stringBuilder.toString()); 951 } 952 953 @Override visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)954 public void visitTableSwitchInsn( 955 final int min, final int max, final Label dflt, final Label... labels) { 956 stringBuilder.setLength(0); 957 for (Label label : labels) { 958 declareLabel(label); 959 } 960 declareLabel(dflt); 961 962 stringBuilder 963 .append(name) 964 .append(".visitTableSwitchInsn(") 965 .append(min) 966 .append(", ") 967 .append(max) 968 .append(", "); 969 appendLabel(dflt); 970 stringBuilder.append(", new Label[] {"); 971 for (int i = 0; i < labels.length; ++i) { 972 stringBuilder.append(i == 0 ? " " : ", "); 973 appendLabel(labels[i]); 974 } 975 stringBuilder.append(END_ARRAY); 976 text.add(stringBuilder.toString()); 977 } 978 979 @Override visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)980 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { 981 stringBuilder.setLength(0); 982 for (Label label : labels) { 983 declareLabel(label); 984 } 985 declareLabel(dflt); 986 987 stringBuilder.append(name).append(".visitLookupSwitchInsn("); 988 appendLabel(dflt); 989 stringBuilder.append(", new int[] {"); 990 for (int i = 0; i < keys.length; ++i) { 991 stringBuilder.append(i == 0 ? " " : ", ").append(keys[i]); 992 } 993 stringBuilder.append(" }, new Label[] {"); 994 for (int i = 0; i < labels.length; ++i) { 995 stringBuilder.append(i == 0 ? " " : ", "); 996 appendLabel(labels[i]); 997 } 998 stringBuilder.append(END_ARRAY); 999 text.add(stringBuilder.toString()); 1000 } 1001 1002 @Override visitMultiANewArrayInsn(final String descriptor, final int numDimensions)1003 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { 1004 stringBuilder.setLength(0); 1005 stringBuilder.append(name).append(".visitMultiANewArrayInsn("); 1006 appendConstant(descriptor); 1007 stringBuilder.append(", ").append(numDimensions).append(");\n"); 1008 text.add(stringBuilder.toString()); 1009 } 1010 1011 @Override visitInsnAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1012 public ASMifier visitInsnAnnotation( 1013 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 1014 return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath, descriptor, visible); 1015 } 1016 1017 @Override visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type)1018 public void visitTryCatchBlock( 1019 final Label start, final Label end, final Label handler, final String type) { 1020 stringBuilder.setLength(0); 1021 declareLabel(start); 1022 declareLabel(end); 1023 declareLabel(handler); 1024 stringBuilder.append(name).append(".visitTryCatchBlock("); 1025 appendLabel(start); 1026 stringBuilder.append(", "); 1027 appendLabel(end); 1028 stringBuilder.append(", "); 1029 appendLabel(handler); 1030 stringBuilder.append(", "); 1031 appendConstant(type); 1032 stringBuilder.append(");\n"); 1033 text.add(stringBuilder.toString()); 1034 } 1035 1036 @Override visitTryCatchAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1037 public ASMifier visitTryCatchAnnotation( 1038 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 1039 return visitTypeAnnotation("visitTryCatchAnnotation", typeRef, typePath, descriptor, visible); 1040 } 1041 1042 @Override visitLocalVariable( final String name, final String descriptor, final String signature, final Label start, final Label end, final int index)1043 public void visitLocalVariable( 1044 final String name, 1045 final String descriptor, 1046 final String signature, 1047 final Label start, 1048 final Label end, 1049 final int index) { 1050 stringBuilder.setLength(0); 1051 stringBuilder.append(this.name).append(".visitLocalVariable("); 1052 appendConstant(name); 1053 stringBuilder.append(", "); 1054 appendConstant(descriptor); 1055 stringBuilder.append(", "); 1056 appendConstant(signature); 1057 stringBuilder.append(", "); 1058 appendLabel(start); 1059 stringBuilder.append(", "); 1060 appendLabel(end); 1061 stringBuilder.append(", ").append(index).append(");\n"); 1062 text.add(stringBuilder.toString()); 1063 } 1064 1065 @Override visitLocalVariableAnnotation( final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, final int[] index, final String descriptor, final boolean visible)1066 public Printer visitLocalVariableAnnotation( 1067 final int typeRef, 1068 final TypePath typePath, 1069 final Label[] start, 1070 final Label[] end, 1071 final int[] index, 1072 final String descriptor, 1073 final boolean visible) { 1074 stringBuilder.setLength(0); 1075 stringBuilder 1076 .append("{\n") 1077 .append(ANNOTATION_VISITOR0) 1078 .append(name) 1079 .append(".visitLocalVariableAnnotation(") 1080 .append(typeRef); 1081 if (typePath == null) { 1082 stringBuilder.append(", null, "); 1083 } else { 1084 stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), "); 1085 } 1086 stringBuilder.append("new Label[] {"); 1087 for (int i = 0; i < start.length; ++i) { 1088 stringBuilder.append(i == 0 ? " " : ", "); 1089 appendLabel(start[i]); 1090 } 1091 stringBuilder.append(" }, new Label[] {"); 1092 for (int i = 0; i < end.length; ++i) { 1093 stringBuilder.append(i == 0 ? " " : ", "); 1094 appendLabel(end[i]); 1095 } 1096 stringBuilder.append(" }, new int[] {"); 1097 for (int i = 0; i < index.length; ++i) { 1098 stringBuilder.append(i == 0 ? " " : ", ").append(index[i]); 1099 } 1100 stringBuilder.append(" }, "); 1101 appendConstant(descriptor); 1102 stringBuilder.append(", ").append(visible).append(");\n"); 1103 text.add(stringBuilder.toString()); 1104 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0); 1105 text.add(asmifier.getText()); 1106 text.add("}\n"); 1107 return asmifier; 1108 } 1109 1110 @Override visitLineNumber(final int line, final Label start)1111 public void visitLineNumber(final int line, final Label start) { 1112 stringBuilder.setLength(0); 1113 stringBuilder.append(name).append(".visitLineNumber(").append(line).append(", "); 1114 appendLabel(start); 1115 stringBuilder.append(");\n"); 1116 text.add(stringBuilder.toString()); 1117 } 1118 1119 @Override visitMaxs(final int maxStack, final int maxLocals)1120 public void visitMaxs(final int maxStack, final int maxLocals) { 1121 stringBuilder.setLength(0); 1122 stringBuilder 1123 .append(name) 1124 .append(".visitMaxs(") 1125 .append(maxStack) 1126 .append(", ") 1127 .append(maxLocals) 1128 .append(");\n"); 1129 text.add(stringBuilder.toString()); 1130 } 1131 1132 @Override visitMethodEnd()1133 public void visitMethodEnd() { 1134 visitMemberEnd(); 1135 } 1136 1137 // ----------------------------------------------------------------------------------------------- 1138 // Common methods 1139 // ----------------------------------------------------------------------------------------------- 1140 1141 /** 1142 * Visits a class, field or method annotation. 1143 * 1144 * @param descriptor the class descriptor of the annotation class. 1145 * @param visible {@literal true} if the annotation is visible at runtime. 1146 * @return a new {@link ASMifier} to visit the annotation values. 1147 */ 1148 // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different. visitAnnotation(final String descriptor, final boolean visible)1149 public ASMifier visitAnnotation(final String descriptor, final boolean visible) { 1150 stringBuilder.setLength(0); 1151 stringBuilder 1152 .append("{\n") 1153 .append(ANNOTATION_VISITOR0) 1154 .append(name) 1155 .append(".visitAnnotation("); 1156 appendConstant(descriptor); 1157 stringBuilder.append(", ").append(visible).append(");\n"); 1158 text.add(stringBuilder.toString()); 1159 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0); 1160 text.add(asmifier.getText()); 1161 text.add("}\n"); 1162 return asmifier; 1163 } 1164 1165 /** 1166 * Visits a class, field or method type annotation. 1167 * 1168 * @param typeRef a reference to the annotated type. The sort of this type reference must be 1169 * {@link org.objectweb.asm.TypeReference#FIELD}. See {@link org.objectweb.asm.TypeReference}. 1170 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or 1171 * static inner type within 'typeRef'. May be {@literal null} if the annotation targets 1172 * 'typeRef' as a whole. 1173 * @param descriptor the class descriptor of the annotation class. 1174 * @param visible {@literal true} if the annotation is visible at runtime. 1175 * @return a new {@link ASMifier} to visit the annotation values. 1176 */ visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1177 public ASMifier visitTypeAnnotation( 1178 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 1179 return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath, descriptor, visible); 1180 } 1181 1182 /** 1183 * Visits a class, field, method, instruction or try catch block type annotation. 1184 * 1185 * @param method the name of the visit method for this type of annotation. 1186 * @param typeRef a reference to the annotated type. The sort of this type reference must be 1187 * {@link org.objectweb.asm.TypeReference#FIELD}. See {@link org.objectweb.asm.TypeReference}. 1188 * @param typePath the path to the annotated type argument, wildcard bound, array element type, or 1189 * static inner type within 'typeRef'. May be {@literal null} if the annotation targets 1190 * 'typeRef' as a whole. 1191 * @param descriptor the class descriptor of the annotation class. 1192 * @param visible {@literal true} if the annotation is visible at runtime. 1193 * @return a new {@link ASMifier} to visit the annotation values. 1194 */ visitTypeAnnotation( final String method, final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1195 public ASMifier visitTypeAnnotation( 1196 final String method, 1197 final int typeRef, 1198 final TypePath typePath, 1199 final String descriptor, 1200 final boolean visible) { 1201 stringBuilder.setLength(0); 1202 stringBuilder 1203 .append("{\n") 1204 .append(ANNOTATION_VISITOR0) 1205 .append(name) 1206 .append('.') 1207 .append(method) 1208 .append('(') 1209 .append(typeRef); 1210 if (typePath == null) { 1211 stringBuilder.append(", null, "); 1212 } else { 1213 stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), "); 1214 } 1215 appendConstant(descriptor); 1216 stringBuilder.append(", ").append(visible).append(");\n"); 1217 text.add(stringBuilder.toString()); 1218 ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0); 1219 text.add(asmifier.getText()); 1220 text.add("}\n"); 1221 return asmifier; 1222 } 1223 1224 /** 1225 * Visit a class, field or method attribute. 1226 * 1227 * @param attribute an attribute. 1228 */ visitAttribute(final Attribute attribute)1229 public void visitAttribute(final Attribute attribute) { 1230 stringBuilder.setLength(0); 1231 stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n'); 1232 if (attribute instanceof ASMifierSupport) { 1233 if (labelNames == null) { 1234 labelNames = new HashMap<>(); 1235 } 1236 stringBuilder.append("{\n"); 1237 ((ASMifierSupport) attribute).asmify(stringBuilder, "attribute", labelNames); 1238 stringBuilder.append(name).append(".visitAttribute(attribute);\n"); 1239 stringBuilder.append("}\n"); 1240 } 1241 text.add(stringBuilder.toString()); 1242 } 1243 1244 /** Visits the end of a field, record component or method. */ visitMemberEnd()1245 private void visitMemberEnd() { 1246 stringBuilder.setLength(0); 1247 stringBuilder.append(name).append(VISIT_END); 1248 text.add(stringBuilder.toString()); 1249 } 1250 1251 // ----------------------------------------------------------------------------------------------- 1252 // Utility methods 1253 // ----------------------------------------------------------------------------------------------- 1254 1255 /** 1256 * Constructs a new {@link ASMifier}. 1257 * 1258 * @param visitorVariableName the name of the visitor variable in the produced code. 1259 * @param annotationVisitorId identifier of the annotation visitor variable in the produced code. 1260 * @return a new {@link ASMifier}. 1261 */ 1262 // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). createASMifier( final String visitorVariableName, final int annotationVisitorId)1263 protected ASMifier createASMifier( 1264 final String visitorVariableName, final int annotationVisitorId) { 1265 return new ASMifier(api, visitorVariableName, annotationVisitorId); 1266 } 1267 1268 /** 1269 * Appends a string representation of the given access flags to {@link #stringBuilder}. 1270 * 1271 * @param accessFlags some access flags. 1272 */ appendAccessFlags(final int accessFlags)1273 private void appendAccessFlags(final int accessFlags) { 1274 boolean isEmpty = true; 1275 if ((accessFlags & Opcodes.ACC_PUBLIC) != 0) { 1276 stringBuilder.append("ACC_PUBLIC"); 1277 isEmpty = false; 1278 } 1279 if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) { 1280 stringBuilder.append("ACC_PRIVATE"); 1281 isEmpty = false; 1282 } 1283 if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) { 1284 stringBuilder.append("ACC_PROTECTED"); 1285 isEmpty = false; 1286 } 1287 if ((accessFlags & Opcodes.ACC_FINAL) != 0) { 1288 if (!isEmpty) { 1289 stringBuilder.append(" | "); 1290 } 1291 stringBuilder.append("ACC_FINAL"); 1292 isEmpty = false; 1293 } 1294 if ((accessFlags & Opcodes.ACC_STATIC) != 0) { 1295 if (!isEmpty) { 1296 stringBuilder.append(" | "); 1297 } 1298 stringBuilder.append("ACC_STATIC"); 1299 isEmpty = false; 1300 } 1301 if ((accessFlags & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE)) 1302 != 0) { 1303 if (!isEmpty) { 1304 stringBuilder.append(" | "); 1305 } 1306 if ((accessFlags & ACCESS_CLASS) == 0) { 1307 if ((accessFlags & ACCESS_MODULE) == 0) { 1308 stringBuilder.append("ACC_SYNCHRONIZED"); 1309 } else { 1310 stringBuilder.append("ACC_TRANSITIVE"); 1311 } 1312 } else { 1313 stringBuilder.append("ACC_SUPER"); 1314 } 1315 isEmpty = false; 1316 } 1317 if ((accessFlags & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE)) 1318 != 0) { 1319 if (!isEmpty) { 1320 stringBuilder.append(" | "); 1321 } 1322 if ((accessFlags & ACCESS_FIELD) == 0) { 1323 if ((accessFlags & ACCESS_MODULE) == 0) { 1324 stringBuilder.append("ACC_BRIDGE"); 1325 } else { 1326 stringBuilder.append("ACC_STATIC_PHASE"); 1327 } 1328 } else { 1329 stringBuilder.append("ACC_VOLATILE"); 1330 } 1331 isEmpty = false; 1332 } 1333 if ((accessFlags & Opcodes.ACC_VARARGS) != 0 1334 && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) { 1335 if (!isEmpty) { 1336 stringBuilder.append(" | "); 1337 } 1338 stringBuilder.append("ACC_VARARGS"); 1339 isEmpty = false; 1340 } 1341 if ((accessFlags & Opcodes.ACC_TRANSIENT) != 0 && (accessFlags & ACCESS_FIELD) != 0) { 1342 if (!isEmpty) { 1343 stringBuilder.append(" | "); 1344 } 1345 stringBuilder.append("ACC_TRANSIENT"); 1346 isEmpty = false; 1347 } 1348 if ((accessFlags & Opcodes.ACC_NATIVE) != 0 1349 && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) { 1350 if (!isEmpty) { 1351 stringBuilder.append(" | "); 1352 } 1353 stringBuilder.append("ACC_NATIVE"); 1354 isEmpty = false; 1355 } 1356 if ((accessFlags & Opcodes.ACC_ENUM) != 0 1357 && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD | ACCESS_INNER)) != 0) { 1358 if (!isEmpty) { 1359 stringBuilder.append(" | "); 1360 } 1361 stringBuilder.append("ACC_ENUM"); 1362 isEmpty = false; 1363 } 1364 if ((accessFlags & Opcodes.ACC_ANNOTATION) != 0 1365 && (accessFlags & (ACCESS_CLASS | ACCESS_INNER)) != 0) { 1366 if (!isEmpty) { 1367 stringBuilder.append(" | "); 1368 } 1369 stringBuilder.append("ACC_ANNOTATION"); 1370 isEmpty = false; 1371 } 1372 if ((accessFlags & Opcodes.ACC_ABSTRACT) != 0) { 1373 if (!isEmpty) { 1374 stringBuilder.append(" | "); 1375 } 1376 stringBuilder.append("ACC_ABSTRACT"); 1377 isEmpty = false; 1378 } 1379 if ((accessFlags & Opcodes.ACC_INTERFACE) != 0) { 1380 if (!isEmpty) { 1381 stringBuilder.append(" | "); 1382 } 1383 stringBuilder.append("ACC_INTERFACE"); 1384 isEmpty = false; 1385 } 1386 if ((accessFlags & Opcodes.ACC_STRICT) != 0) { 1387 if (!isEmpty) { 1388 stringBuilder.append(" | "); 1389 } 1390 stringBuilder.append("ACC_STRICT"); 1391 isEmpty = false; 1392 } 1393 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0) { 1394 if (!isEmpty) { 1395 stringBuilder.append(" | "); 1396 } 1397 stringBuilder.append("ACC_SYNTHETIC"); 1398 isEmpty = false; 1399 } 1400 if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { 1401 if (!isEmpty) { 1402 stringBuilder.append(" | "); 1403 } 1404 stringBuilder.append("ACC_DEPRECATED"); 1405 isEmpty = false; 1406 } 1407 if ((accessFlags & Opcodes.ACC_RECORD) != 0) { 1408 if (!isEmpty) { 1409 stringBuilder.append(" | "); 1410 } 1411 stringBuilder.append("ACC_RECORD"); 1412 isEmpty = false; 1413 } 1414 if ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) { 1415 if (!isEmpty) { 1416 stringBuilder.append(" | "); 1417 } 1418 if ((accessFlags & ACCESS_CLASS) == 0) { 1419 stringBuilder.append("ACC_MANDATED"); 1420 } else { 1421 stringBuilder.append("ACC_MODULE"); 1422 } 1423 isEmpty = false; 1424 } 1425 if (isEmpty) { 1426 stringBuilder.append('0'); 1427 } 1428 } 1429 1430 /** 1431 * Appends a string representation of the given constant to {@link #stringBuilder}. 1432 * 1433 * @param value a {@link String}, {@link Type}, {@link Handle}, {@link Byte}, {@link Short}, 1434 * {@link Character}, {@link Integer}, {@link Float}, {@link Long} or {@link Double} object, 1435 * or an array of primitive values. May be {@literal null}. 1436 */ appendConstant(final Object value)1437 protected void appendConstant(final Object value) { 1438 if (value == null) { 1439 stringBuilder.append("null"); 1440 } else if (value instanceof String) { 1441 appendString(stringBuilder, (String) value); 1442 } else if (value instanceof Type) { 1443 stringBuilder.append("Type.getType(\""); 1444 stringBuilder.append(((Type) value).getDescriptor()); 1445 stringBuilder.append("\")"); 1446 } else if (value instanceof Handle) { 1447 stringBuilder.append("new Handle("); 1448 Handle handle = (Handle) value; 1449 stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \""); 1450 stringBuilder.append(handle.getOwner()).append(COMMA); 1451 stringBuilder.append(handle.getName()).append(COMMA); 1452 stringBuilder.append(handle.getDesc()).append("\", "); 1453 stringBuilder.append(handle.isInterface()).append(')'); 1454 } else if (value instanceof ConstantDynamic) { 1455 stringBuilder.append("new ConstantDynamic(\""); 1456 ConstantDynamic constantDynamic = (ConstantDynamic) value; 1457 stringBuilder.append(constantDynamic.getName()).append(COMMA); 1458 stringBuilder.append(constantDynamic.getDescriptor()).append("\", "); 1459 appendConstant(constantDynamic.getBootstrapMethod()); 1460 stringBuilder.append(NEW_OBJECT_ARRAY); 1461 int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount(); 1462 for (int i = 0; i < bootstrapMethodArgumentCount; ++i) { 1463 appendConstant(constantDynamic.getBootstrapMethodArgument(i)); 1464 if (i != bootstrapMethodArgumentCount - 1) { 1465 stringBuilder.append(", "); 1466 } 1467 } 1468 stringBuilder.append("})"); 1469 } else if (value instanceof Byte) { 1470 stringBuilder.append("new Byte((byte)").append(value).append(')'); 1471 } else if (value instanceof Boolean) { 1472 stringBuilder.append(((Boolean) value).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE"); 1473 } else if (value instanceof Short) { 1474 stringBuilder.append("new Short((short)").append(value).append(')'); 1475 } else if (value instanceof Character) { 1476 stringBuilder 1477 .append("new Character((char)") 1478 .append((int) ((Character) value).charValue()) 1479 .append(')'); 1480 } else if (value instanceof Integer) { 1481 stringBuilder.append("new Integer(").append(value).append(')'); 1482 } else if (value instanceof Float) { 1483 stringBuilder.append("new Float(\"").append(value).append("\")"); 1484 } else if (value instanceof Long) { 1485 stringBuilder.append("new Long(").append(value).append("L)"); 1486 } else if (value instanceof Double) { 1487 stringBuilder.append("new Double(\"").append(value).append("\")"); 1488 } else if (value instanceof byte[]) { 1489 byte[] byteArray = (byte[]) value; 1490 stringBuilder.append("new byte[] {"); 1491 for (int i = 0; i < byteArray.length; i++) { 1492 stringBuilder.append(i == 0 ? "" : ",").append(byteArray[i]); 1493 } 1494 stringBuilder.append('}'); 1495 } else if (value instanceof boolean[]) { 1496 boolean[] booleanArray = (boolean[]) value; 1497 stringBuilder.append("new boolean[] {"); 1498 for (int i = 0; i < booleanArray.length; i++) { 1499 stringBuilder.append(i == 0 ? "" : ",").append(booleanArray[i]); 1500 } 1501 stringBuilder.append('}'); 1502 } else if (value instanceof short[]) { 1503 short[] shortArray = (short[]) value; 1504 stringBuilder.append("new short[] {"); 1505 for (int i = 0; i < shortArray.length; i++) { 1506 stringBuilder.append(i == 0 ? "" : ",").append("(short)").append(shortArray[i]); 1507 } 1508 stringBuilder.append('}'); 1509 } else if (value instanceof char[]) { 1510 char[] charArray = (char[]) value; 1511 stringBuilder.append("new char[] {"); 1512 for (int i = 0; i < charArray.length; i++) { 1513 stringBuilder.append(i == 0 ? "" : ",").append("(char)").append((int) charArray[i]); 1514 } 1515 stringBuilder.append('}'); 1516 } else if (value instanceof int[]) { 1517 int[] intArray = (int[]) value; 1518 stringBuilder.append("new int[] {"); 1519 for (int i = 0; i < intArray.length; i++) { 1520 stringBuilder.append(i == 0 ? "" : ",").append(intArray[i]); 1521 } 1522 stringBuilder.append('}'); 1523 } else if (value instanceof long[]) { 1524 long[] longArray = (long[]) value; 1525 stringBuilder.append("new long[] {"); 1526 for (int i = 0; i < longArray.length; i++) { 1527 stringBuilder.append(i == 0 ? "" : ",").append(longArray[i]).append('L'); 1528 } 1529 stringBuilder.append('}'); 1530 } else if (value instanceof float[]) { 1531 float[] floatArray = (float[]) value; 1532 stringBuilder.append("new float[] {"); 1533 for (int i = 0; i < floatArray.length; i++) { 1534 stringBuilder.append(i == 0 ? "" : ",").append(floatArray[i]).append('f'); 1535 } 1536 stringBuilder.append('}'); 1537 } else if (value instanceof double[]) { 1538 double[] doubleArray = (double[]) value; 1539 stringBuilder.append("new double[] {"); 1540 for (int i = 0; i < doubleArray.length; i++) { 1541 stringBuilder.append(i == 0 ? "" : ",").append(doubleArray[i]).append('d'); 1542 } 1543 stringBuilder.append('}'); 1544 } 1545 } 1546 1547 /** 1548 * Calls {@link #declareLabel} for each label in the given stack map frame types. 1549 * 1550 * @param numTypes the number of stack map frame types in 'frameTypes'. 1551 * @param frameTypes an array of stack map frame types, in the format described in {@link 1552 * org.objectweb.asm.MethodVisitor#visitFrame}. 1553 */ declareFrameTypes(final int numTypes, final Object[] frameTypes)1554 private void declareFrameTypes(final int numTypes, final Object[] frameTypes) { 1555 for (int i = 0; i < numTypes; ++i) { 1556 if (frameTypes[i] instanceof Label) { 1557 declareLabel((Label) frameTypes[i]); 1558 } 1559 } 1560 } 1561 1562 /** 1563 * Appends the given stack map frame types to {@link #stringBuilder}. 1564 * 1565 * @param numTypes the number of stack map frame types in 'frameTypes'. 1566 * @param frameTypes an array of stack map frame types, in the format described in {@link 1567 * org.objectweb.asm.MethodVisitor#visitFrame}. 1568 */ appendFrameTypes(final int numTypes, final Object[] frameTypes)1569 private void appendFrameTypes(final int numTypes, final Object[] frameTypes) { 1570 for (int i = 0; i < numTypes; ++i) { 1571 if (i > 0) { 1572 stringBuilder.append(", "); 1573 } 1574 if (frameTypes[i] instanceof String) { 1575 appendConstant(frameTypes[i]); 1576 } else if (frameTypes[i] instanceof Integer) { 1577 stringBuilder.append(FRAME_TYPES.get(((Integer) frameTypes[i]).intValue())); 1578 } else { 1579 appendLabel((Label) frameTypes[i]); 1580 } 1581 } 1582 } 1583 1584 /** 1585 * Appends a declaration of the given label to {@link #stringBuilder}. This declaration is of the 1586 * form "Label labelXXX = new Label();". Does nothing if the given label has already been 1587 * declared. 1588 * 1589 * @param label a label. 1590 */ declareLabel(final Label label)1591 protected void declareLabel(final Label label) { 1592 if (labelNames == null) { 1593 labelNames = new HashMap<>(); 1594 } 1595 String labelName = labelNames.get(label); 1596 if (labelName == null) { 1597 labelName = "label" + labelNames.size(); 1598 labelNames.put(label, labelName); 1599 stringBuilder.append("Label ").append(labelName).append(" = new Label();\n"); 1600 } 1601 } 1602 1603 /** 1604 * Appends the name of the given label to {@link #stringBuilder}. The given label <i>must</i> 1605 * already have a name. One way to ensure this is to always call {@link #declareLabel} before 1606 * calling this method. 1607 * 1608 * @param label a label. 1609 */ appendLabel(final Label label)1610 protected void appendLabel(final Label label) { 1611 stringBuilder.append(labelNames.get(label)); 1612 } 1613 } 1614