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