1/*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2005 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30package com.sleepycat.asm; 31 32/** 33 * A {@link MethodVisitor} that generates methods in bytecode form. Each visit 34 * method of this class appends the bytecode corresponding to the visited 35 * instruction to a byte vector, in the order these methods are called. 36 * 37 * @author Eric Bruneton 38 */ 39class MethodWriter implements MethodVisitor { 40 41 /** 42 * Next method writer (see {@link ClassWriter#firstMethod firstMethod}). 43 */ 44 MethodWriter next; 45 46 /** 47 * The class writer to which this method must be added. 48 */ 49 ClassWriter cw; 50 51 /** 52 * Access flags of this method. 53 */ 54 private int access; 55 56 /** 57 * The index of the constant pool item that contains the name of this 58 * method. 59 */ 60 private int name; 61 62 /** 63 * The index of the constant pool item that contains the descriptor of this 64 * method. 65 */ 66 private int desc; 67 68 /** 69 * The descriptor of this method. 70 */ 71 private String descriptor; 72 73 /** 74 * If not zero, indicates that the code of this method must be copied from 75 * the ClassReader associated to this writer in <code>cw.cr</code>. More 76 * precisely, this field gives the index of the first byte to copied from 77 * <code>cw.cr.b</code>. 78 */ 79 int classReaderOffset; 80 81 /** 82 * If not zero, indicates that the code of this method must be copied from 83 * the ClassReader associated to this writer in <code>cw.cr</code>. More 84 * precisely, this field gives the number of bytes to copied from 85 * <code>cw.cr.b</code>. 86 */ 87 int classReaderLength; 88 89 /** 90 * The signature of this method. 91 */ 92 String signature; 93 94 /** 95 * Number of exceptions that can be thrown by this method. 96 */ 97 int exceptionCount; 98 99 /** 100 * The exceptions that can be thrown by this method. More precisely, this 101 * array contains the indexes of the constant pool items that contain the 102 * internal names of these exception classes. 103 */ 104 int[] exceptions; 105 106 /** 107 * The annotation default attribute of this method. May be <tt>null</tt>. 108 */ 109 private ByteVector annd; 110 111 /** 112 * The runtime visible annotations of this method. May be <tt>null</tt>. 113 */ 114 private AnnotationWriter anns; 115 116 /** 117 * The runtime invisible annotations of this method. May be <tt>null</tt>. 118 */ 119 private AnnotationWriter ianns; 120 121 /** 122 * The runtime visible parameter annotations of this method. May be 123 * <tt>null</tt>. 124 */ 125 private AnnotationWriter[] panns; 126 127 /** 128 * The runtime invisible parameter annotations of this method. May be 129 * <tt>null</tt>. 130 */ 131 private AnnotationWriter[] ipanns; 132 133 /** 134 * The non standard attributes of the method. 135 */ 136 private Attribute attrs; 137 138 /** 139 * The bytecode of this method. 140 */ 141 private ByteVector code = new ByteVector(); 142 143 /** 144 * Maximum stack size of this method. 145 */ 146 private int maxStack; 147 148 /** 149 * Maximum number of local variables for this method. 150 */ 151 private int maxLocals; 152 153 /** 154 * Number of entries in the catch table of this method. 155 */ 156 private int catchCount; 157 158 /** 159 * The catch table of this method. 160 */ 161 private Handler catchTable; 162 163 /** 164 * The last element in the catchTable handler list. 165 */ 166 private Handler lastHandler; 167 168 /** 169 * Number of entries in the LocalVariableTable attribute. 170 */ 171 private int localVarCount; 172 173 /** 174 * The LocalVariableTable attribute. 175 */ 176 private ByteVector localVar; 177 178 /** 179 * Number of entries in the LocalVariableTypeTable attribute. 180 */ 181 private int localVarTypeCount; 182 183 /** 184 * The LocalVariableTypeTable attribute. 185 */ 186 private ByteVector localVarType; 187 188 /** 189 * Number of entries in the LineNumberTable attribute. 190 */ 191 private int lineNumberCount; 192 193 /** 194 * The LineNumberTable attribute. 195 */ 196 private ByteVector lineNumber; 197 198 /** 199 * The non standard attributes of the method's code. 200 */ 201 private Attribute cattrs; 202 203 /** 204 * Indicates if some jump instructions are too small and need to be resized. 205 */ 206 private boolean resize; 207 208 /* 209 * Fields for the control flow graph analysis algorithm (used to compute the 210 * maximum stack size). A control flow graph contains one node per "basic 211 * block", and one edge per "jump" from one basic block to another. Each 212 * node (i.e., each basic block) is represented by the Label object that 213 * corresponds to the first instruction of this basic block. Each node also 214 * stores the list of its successors in the graph, as a linked list of Edge 215 * objects. 216 */ 217 218 /** 219 * <tt>true</tt> if the maximum stack size and number of local variables 220 * must be automatically computed. 221 */ 222 private final boolean computeMaxs; 223 224 /** 225 * The (relative) stack size after the last visited instruction. This size 226 * is relative to the beginning of the current basic block, i.e., the true 227 * stack size after the last visited instruction is equal to the {@link 228 * Label#beginStackSize beginStackSize} of the current basic block plus 229 * <tt>stackSize</tt>. 230 */ 231 private int stackSize; 232 233 /** 234 * The (relative) maximum stack size after the last visited instruction. 235 * This size is relative to the beginning of the current basic block, i.e., 236 * the true maximum stack size after the last visited instruction is equal 237 * to the {@link Label#beginStackSize beginStackSize} of the current basic 238 * block plus <tt>stackSize</tt>. 239 */ 240 private int maxStackSize; 241 242 /** 243 * The current basic block. This block is the basic block to which the next 244 * instruction to be visited must be added. 245 */ 246 private Label currentBlock; 247 248 /** 249 * The basic block stack used by the control flow analysis algorithm. This 250 * stack is represented by a linked list of {@link Label Label} objects, 251 * linked to each other by their {@link Label#next} field. This stack must 252 * not be confused with the JVM stack used to execute the JVM instructions! 253 */ 254 private Label blockStack; 255 256 /** 257 * The stack size variation corresponding to each JVM instruction. This 258 * stack variation is equal to the size of the values produced by an 259 * instruction, minus the size of the values consumed by this instruction. 260 */ 261 private final static int[] SIZE; 262 263 // ------------------------------------------------------------------------ 264 // Static initializer 265 // ------------------------------------------------------------------------ 266 267 /** 268 * Computes the stack size variation corresponding to each JVM instruction. 269 */ 270 static { 271 int i; 272 int[] b = new int[202]; 273 String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" 274 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" 275 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" 276 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; 277 for (i = 0; i < b.length; ++i) { 278 b[i] = s.charAt(i) - 'E'; 279 } 280 SIZE = b; 281 282 // code to generate the above string 283 // 284 // int NA = 0; // not applicable (unused opcode or variable size opcode) 285 // 286 // b = new int[] { 287 // 0, //NOP, // visitInsn 288 // 1, //ACONST_NULL, // - 289 // 1, //ICONST_M1, // - 290 // 1, //ICONST_0, // - 291 // 1, //ICONST_1, // - 292 // 1, //ICONST_2, // - 293 // 1, //ICONST_3, // - 294 // 1, //ICONST_4, // - 295 // 1, //ICONST_5, // - 296 // 2, //LCONST_0, // - 297 // 2, //LCONST_1, // - 298 // 1, //FCONST_0, // - 299 // 1, //FCONST_1, // - 300 // 1, //FCONST_2, // - 301 // 2, //DCONST_0, // - 302 // 2, //DCONST_1, // - 303 // 1, //BIPUSH, // visitIntInsn 304 // 1, //SIPUSH, // - 305 // 1, //LDC, // visitLdcInsn 306 // NA, //LDC_W, // - 307 // NA, //LDC2_W, // - 308 // 1, //ILOAD, // visitVarInsn 309 // 2, //LLOAD, // - 310 // 1, //FLOAD, // - 311 // 2, //DLOAD, // - 312 // 1, //ALOAD, // - 313 // NA, //ILOAD_0, // - 314 // NA, //ILOAD_1, // - 315 // NA, //ILOAD_2, // - 316 // NA, //ILOAD_3, // - 317 // NA, //LLOAD_0, // - 318 // NA, //LLOAD_1, // - 319 // NA, //LLOAD_2, // - 320 // NA, //LLOAD_3, // - 321 // NA, //FLOAD_0, // - 322 // NA, //FLOAD_1, // - 323 // NA, //FLOAD_2, // - 324 // NA, //FLOAD_3, // - 325 // NA, //DLOAD_0, // - 326 // NA, //DLOAD_1, // - 327 // NA, //DLOAD_2, // - 328 // NA, //DLOAD_3, // - 329 // NA, //ALOAD_0, // - 330 // NA, //ALOAD_1, // - 331 // NA, //ALOAD_2, // - 332 // NA, //ALOAD_3, // - 333 // -1, //IALOAD, // visitInsn 334 // 0, //LALOAD, // - 335 // -1, //FALOAD, // - 336 // 0, //DALOAD, // - 337 // -1, //AALOAD, // - 338 // -1, //BALOAD, // - 339 // -1, //CALOAD, // - 340 // -1, //SALOAD, // - 341 // -1, //ISTORE, // visitVarInsn 342 // -2, //LSTORE, // - 343 // -1, //FSTORE, // - 344 // -2, //DSTORE, // - 345 // -1, //ASTORE, // - 346 // NA, //ISTORE_0, // - 347 // NA, //ISTORE_1, // - 348 // NA, //ISTORE_2, // - 349 // NA, //ISTORE_3, // - 350 // NA, //LSTORE_0, // - 351 // NA, //LSTORE_1, // - 352 // NA, //LSTORE_2, // - 353 // NA, //LSTORE_3, // - 354 // NA, //FSTORE_0, // - 355 // NA, //FSTORE_1, // - 356 // NA, //FSTORE_2, // - 357 // NA, //FSTORE_3, // - 358 // NA, //DSTORE_0, // - 359 // NA, //DSTORE_1, // - 360 // NA, //DSTORE_2, // - 361 // NA, //DSTORE_3, // - 362 // NA, //ASTORE_0, // - 363 // NA, //ASTORE_1, // - 364 // NA, //ASTORE_2, // - 365 // NA, //ASTORE_3, // - 366 // -3, //IASTORE, // visitInsn 367 // -4, //LASTORE, // - 368 // -3, //FASTORE, // - 369 // -4, //DASTORE, // - 370 // -3, //AASTORE, // - 371 // -3, //BASTORE, // - 372 // -3, //CASTORE, // - 373 // -3, //SASTORE, // - 374 // -1, //POP, // - 375 // -2, //POP2, // - 376 // 1, //DUP, // - 377 // 1, //DUP_X1, // - 378 // 1, //DUP_X2, // - 379 // 2, //DUP2, // - 380 // 2, //DUP2_X1, // - 381 // 2, //DUP2_X2, // - 382 // 0, //SWAP, // - 383 // -1, //IADD, // - 384 // -2, //LADD, // - 385 // -1, //FADD, // - 386 // -2, //DADD, // - 387 // -1, //ISUB, // - 388 // -2, //LSUB, // - 389 // -1, //FSUB, // - 390 // -2, //DSUB, // - 391 // -1, //IMUL, // - 392 // -2, //LMUL, // - 393 // -1, //FMUL, // - 394 // -2, //DMUL, // - 395 // -1, //IDIV, // - 396 // -2, //LDIV, // - 397 // -1, //FDIV, // - 398 // -2, //DDIV, // - 399 // -1, //IREM, // - 400 // -2, //LREM, // - 401 // -1, //FREM, // - 402 // -2, //DREM, // - 403 // 0, //INEG, // - 404 // 0, //LNEG, // - 405 // 0, //FNEG, // - 406 // 0, //DNEG, // - 407 // -1, //ISHL, // - 408 // -1, //LSHL, // - 409 // -1, //ISHR, // - 410 // -1, //LSHR, // - 411 // -1, //IUSHR, // - 412 // -1, //LUSHR, // - 413 // -1, //IAND, // - 414 // -2, //LAND, // - 415 // -1, //IOR, // - 416 // -2, //LOR, // - 417 // -1, //IXOR, // - 418 // -2, //LXOR, // - 419 // 0, //IINC, // visitIincInsn 420 // 1, //I2L, // visitInsn 421 // 0, //I2F, // - 422 // 1, //I2D, // - 423 // -1, //L2I, // - 424 // -1, //L2F, // - 425 // 0, //L2D, // - 426 // 0, //F2I, // - 427 // 1, //F2L, // - 428 // 1, //F2D, // - 429 // -1, //D2I, // - 430 // 0, //D2L, // - 431 // -1, //D2F, // - 432 // 0, //I2B, // - 433 // 0, //I2C, // - 434 // 0, //I2S, // - 435 // -3, //LCMP, // - 436 // -1, //FCMPL, // - 437 // -1, //FCMPG, // - 438 // -3, //DCMPL, // - 439 // -3, //DCMPG, // - 440 // -1, //IFEQ, // visitJumpInsn 441 // -1, //IFNE, // - 442 // -1, //IFLT, // - 443 // -1, //IFGE, // - 444 // -1, //IFGT, // - 445 // -1, //IFLE, // - 446 // -2, //IF_ICMPEQ, // - 447 // -2, //IF_ICMPNE, // - 448 // -2, //IF_ICMPLT, // - 449 // -2, //IF_ICMPGE, // - 450 // -2, //IF_ICMPGT, // - 451 // -2, //IF_ICMPLE, // - 452 // -2, //IF_ACMPEQ, // - 453 // -2, //IF_ACMPNE, // - 454 // 0, //GOTO, // - 455 // 1, //JSR, // - 456 // 0, //RET, // visitVarInsn 457 // -1, //TABLESWITCH, // visiTableSwitchInsn 458 // -1, //LOOKUPSWITCH, // visitLookupSwitch 459 // -1, //IRETURN, // visitInsn 460 // -2, //LRETURN, // - 461 // -1, //FRETURN, // - 462 // -2, //DRETURN, // - 463 // -1, //ARETURN, // - 464 // 0, //RETURN, // - 465 // NA, //GETSTATIC, // visitFieldInsn 466 // NA, //PUTSTATIC, // - 467 // NA, //GETFIELD, // - 468 // NA, //PUTFIELD, // - 469 // NA, //INVOKEVIRTUAL, // visitMethodInsn 470 // NA, //INVOKESPECIAL, // - 471 // NA, //INVOKESTATIC, // - 472 // NA, //INVOKEINTERFACE, // - 473 // NA, //UNUSED, // NOT VISITED 474 // 1, //NEW, // visitTypeInsn 475 // 0, //NEWARRAY, // visitIntInsn 476 // 0, //ANEWARRAY, // visitTypeInsn 477 // 0, //ARRAYLENGTH, // visitInsn 478 // NA, //ATHROW, // - 479 // 0, //CHECKCAST, // visitTypeInsn 480 // 0, //INSTANCEOF, // - 481 // -1, //MONITORENTER, // visitInsn 482 // -1, //MONITOREXIT, // - 483 // NA, //WIDE, // NOT VISITED 484 // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn 485 // -1, //IFNULL, // visitJumpInsn 486 // -1, //IFNONNULL, // - 487 // NA, //GOTO_W, // - 488 // NA, //JSR_W, // - 489 // }; 490 // for (i = 0; i < b.length; ++i) { 491 // System.err.print((char)('E' + b[i])); 492 // } 493 // System.err.println(); 494 } 495 496 // ------------------------------------------------------------------------ 497 // Constructor 498 // ------------------------------------------------------------------------ 499 500 /** 501 * Constructs a new {@link MethodWriter}. 502 * 503 * @param cw the class writer in which the method must be added. 504 * @param access the method's access flags (see {@link Opcodes}). 505 * @param name the method's name. 506 * @param desc the method's descriptor (see {@link Type}). 507 * @param signature the method's signature. May be <tt>null</tt>. 508 * @param exceptions the internal names of the method's exceptions. May be 509 * <tt>null</tt>. 510 * @param computeMaxs <tt>true</tt> if the maximum stack size and number 511 * of local variables must be automatically computed. 512 */ 513 MethodWriter( 514 final ClassWriter cw, 515 final int access, 516 final String name, 517 final String desc, 518 final String signature, 519 final String[] exceptions, 520 final boolean computeMaxs) 521 { 522 if (cw.firstMethod == null) { 523 cw.firstMethod = this; 524 } else { 525 cw.lastMethod.next = this; 526 } 527 cw.lastMethod = this; 528 this.cw = cw; 529 this.access = access; 530 this.name = cw.newUTF8(name); 531 this.desc = cw.newUTF8(desc); 532 this.descriptor = desc; 533 this.signature = signature; 534 if (exceptions != null && exceptions.length > 0) { 535 exceptionCount = exceptions.length; 536 this.exceptions = new int[exceptionCount]; 537 for (int i = 0; i < exceptionCount; ++i) { 538 this.exceptions[i] = cw.newClass(exceptions[i]); 539 } 540 } 541 this.computeMaxs = computeMaxs; 542 if (computeMaxs) { 543 // updates maxLocals 544 int size = getArgumentsAndReturnSizes(desc) >> 2; 545 if ((access & Opcodes.ACC_STATIC) != 0) { 546 --size; 547 } 548 maxLocals = size; 549 // pushes the first block onto the stack of blocks to be visited 550 currentBlock = new Label(); 551 currentBlock.pushed = true; 552 blockStack = currentBlock; 553 } 554 } 555 556 // ------------------------------------------------------------------------ 557 // Implementation of the MethodVisitor interface 558 // ------------------------------------------------------------------------ 559 560 public AnnotationVisitor visitAnnotationDefault() { 561 annd = new ByteVector(); 562 return new AnnotationWriter(cw, false, annd, null, 0); 563 } 564 565 public AnnotationVisitor visitAnnotation( 566 final String desc, 567 final boolean visible) 568 { 569 ByteVector bv = new ByteVector(); 570 // write type, and reserve space for values count 571 bv.putShort(cw.newUTF8(desc)).putShort(0); 572 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 573 if (visible) { 574 aw.next = anns; 575 anns = aw; 576 } else { 577 aw.next = ianns; 578 ianns = aw; 579 } 580 return aw; 581 } 582 583 public AnnotationVisitor visitParameterAnnotation( 584 final int parameter, 585 final String desc, 586 final boolean visible) 587 { 588 ByteVector bv = new ByteVector(); 589 // write type, and reserve space for values count 590 bv.putShort(cw.newUTF8(desc)).putShort(0); 591 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 592 if (visible) { 593 if (panns == null) { 594 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 595 } 596 aw.next = panns[parameter]; 597 panns[parameter] = aw; 598 } else { 599 if (ipanns == null) { 600 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 601 } 602 aw.next = ipanns[parameter]; 603 ipanns[parameter] = aw; 604 } 605 return aw; 606 } 607 608 public void visitAttribute(final Attribute attr) { 609 if (attr.isCodeAttribute()) { 610 attr.next = cattrs; 611 cattrs = attr; 612 } else { 613 attr.next = attrs; 614 attrs = attr; 615 } 616 } 617 618 public void visitCode() { 619 } 620 621 public void visitInsn(final int opcode) { 622 if (computeMaxs) { 623 // updates current and max stack sizes 624 int size = stackSize + SIZE[opcode]; 625 if (size > maxStackSize) { 626 maxStackSize = size; 627 } 628 stackSize = size; 629 // if opcode == ATHROW or xRETURN, ends current block (no successor) 630 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) 631 || opcode == Opcodes.ATHROW) 632 { 633 if (currentBlock != null) { 634 currentBlock.maxStackSize = maxStackSize; 635 currentBlock = null; 636 } 637 } 638 } 639 // adds the instruction to the bytecode of the method 640 code.putByte(opcode); 641 } 642 643 public void visitIntInsn(final int opcode, final int operand) { 644 if (computeMaxs && opcode != Opcodes.NEWARRAY) { 645 // updates current and max stack sizes only if opcode == NEWARRAY 646 // (stack size variation = 0 for BIPUSH or SIPUSH) 647 int size = stackSize + 1; 648 if (size > maxStackSize) { 649 maxStackSize = size; 650 } 651 stackSize = size; 652 } 653 // adds the instruction to the bytecode of the method 654 if (opcode == Opcodes.SIPUSH) { 655 code.put12(opcode, operand); 656 } else { // BIPUSH or NEWARRAY 657 code.put11(opcode, operand); 658 } 659 } 660 661 public void visitVarInsn(final int opcode, final int var) { 662 if (computeMaxs) { 663 // updates current and max stack sizes 664 if (opcode == Opcodes.RET) { 665 // no stack change, but end of current block (no successor) 666 if (currentBlock != null) { 667 currentBlock.maxStackSize = maxStackSize; 668 currentBlock = null; 669 } 670 } else { // xLOAD or xSTORE 671 int size = stackSize + SIZE[opcode]; 672 if (size > maxStackSize) { 673 maxStackSize = size; 674 } 675 stackSize = size; 676 } 677 // updates max locals 678 int n; 679 if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD 680 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) 681 { 682 n = var + 2; 683 } else { 684 n = var + 1; 685 } 686 if (n > maxLocals) { 687 maxLocals = n; 688 } 689 } 690 // adds the instruction to the bytecode of the method 691 if (var < 4 && opcode != Opcodes.RET) { 692 int opt; 693 if (opcode < Opcodes.ISTORE) { 694 /* ILOAD_0 */ 695 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; 696 } else { 697 /* ISTORE_0 */ 698 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; 699 } 700 code.putByte(opt); 701 } else if (var >= 256) { 702 code.putByte(196 /* WIDE */).put12(opcode, var); 703 } else { 704 code.put11(opcode, var); 705 } 706 } 707 708 public void visitTypeInsn(final int opcode, final String desc) { 709 if (computeMaxs && opcode == Opcodes.NEW) { 710 // updates current and max stack sizes only if opcode == NEW 711 // (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF) 712 int size = stackSize + 1; 713 if (size > maxStackSize) { 714 maxStackSize = size; 715 } 716 stackSize = size; 717 } 718 // adds the instruction to the bytecode of the method 719 code.put12(opcode, cw.newClass(desc)); 720 } 721 722 public void visitFieldInsn( 723 final int opcode, 724 final String owner, 725 final String name, 726 final String desc) 727 { 728 if (computeMaxs) { 729 int size; 730 // computes the stack size variation 731 char c = desc.charAt(0); 732 switch (opcode) { 733 case Opcodes.GETSTATIC: 734 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); 735 break; 736 case Opcodes.PUTSTATIC: 737 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); 738 break; 739 case Opcodes.GETFIELD: 740 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); 741 break; 742 // case Constants.PUTFIELD: 743 default: 744 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); 745 break; 746 } 747 // updates current and max stack sizes 748 if (size > maxStackSize) { 749 maxStackSize = size; 750 } 751 stackSize = size; 752 } 753 // adds the instruction to the bytecode of the method 754 code.put12(opcode, cw.newField(owner, name, desc)); 755 } 756 757 public void visitMethodInsn( 758 final int opcode, 759 final String owner, 760 final String name, 761 final String desc) 762 { 763 boolean itf = opcode == Opcodes.INVOKEINTERFACE; 764 Item i = cw.newMethodItem(owner, name, desc, itf); 765 int argSize = i.intVal; 766 if (computeMaxs) { 767 /* 768 * computes the stack size variation. In order not to recompute 769 * several times this variation for the same Item, we use the intVal 770 * field of this item to store this variation, once it has been 771 * computed. More precisely this intVal field stores the sizes of 772 * the arguments and of the return value corresponding to desc. 773 */ 774 if (argSize == 0) { 775 // the above sizes have not been computed yet, so we compute 776 // them... 777 argSize = getArgumentsAndReturnSizes(desc); 778 // ... and we save them in order not to recompute them in the 779 // future 780 i.intVal = argSize; 781 } 782 int size; 783 if (opcode == Opcodes.INVOKESTATIC) { 784 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; 785 } else { 786 size = stackSize - (argSize >> 2) + (argSize & 0x03); 787 } 788 // updates current and max stack sizes 789 if (size > maxStackSize) { 790 maxStackSize = size; 791 } 792 stackSize = size; 793 } 794 // adds the instruction to the bytecode of the method 795 if (itf) { 796 if (!computeMaxs) { 797 if (argSize == 0) { 798 argSize = getArgumentsAndReturnSizes(desc); 799 i.intVal = argSize; 800 } 801 } 802 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); 803 } else { 804 code.put12(opcode, i.index); 805 } 806 } 807 808 public void visitJumpInsn(final int opcode, final Label label) { 809 if (computeMaxs) { 810 if (opcode == Opcodes.GOTO) { 811 // no stack change, but end of current block (with one new 812 // successor) 813 if (currentBlock != null) { 814 currentBlock.maxStackSize = maxStackSize; 815 addSuccessor(stackSize, label); 816 currentBlock = null; 817 } 818 } else if (opcode == Opcodes.JSR) { 819 if (currentBlock != null) { 820 addSuccessor(stackSize + 1, label); 821 } 822 } else { 823 // updates current stack size (max stack size unchanged because 824 // stack size variation always negative in this case) 825 stackSize += SIZE[opcode]; 826 if (currentBlock != null) { 827 addSuccessor(stackSize, label); 828 } 829 } 830 } 831 // adds the instruction to the bytecode of the method 832 if (label.resolved && label.position - code.length < Short.MIN_VALUE) { 833 /* 834 * case of a backward jump with an offset < -32768. In this case we 835 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx 836 * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the 837 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'> 838 * designates the instruction just after the GOTO_W. 839 */ 840 if (opcode == Opcodes.GOTO) { 841 code.putByte(200); // GOTO_W 842 } else if (opcode == Opcodes.JSR) { 843 code.putByte(201); // JSR_W 844 } else { 845 code.putByte(opcode <= 166 846 ? ((opcode + 1) ^ 1) - 1 847 : opcode ^ 1); 848 code.putShort(8); // jump offset 849 code.putByte(200); // GOTO_W 850 } 851 label.put(this, code, code.length - 1, true); 852 } else { 853 /* 854 * case of a backward jump with an offset >= -32768, or of a forward 855 * jump with, of course, an unknown offset. In these cases we store 856 * the offset in 2 bytes (which will be increased in 857 * resizeInstructions, if needed). 858 */ 859 code.putByte(opcode); 860 label.put(this, code, code.length - 1, false); 861 } 862 } 863 864 public void visitLabel(final Label label) { 865 if (computeMaxs) { 866 if (currentBlock != null) { 867 // ends current block (with one new successor) 868 currentBlock.maxStackSize = maxStackSize; 869 addSuccessor(stackSize, label); 870 } 871 // begins a new current block, 872 // resets the relative current and max stack sizes 873 currentBlock = label; 874 stackSize = 0; 875 maxStackSize = 0; 876 } 877 // resolves previous forward references to label, if any 878 resize |= label.resolve(this, code.length, code.data); 879 } 880 881 public void visitLdcInsn(final Object cst) { 882 Item i = cw.newConstItem(cst); 883 if (computeMaxs) { 884 int size; 885 // computes the stack size variation 886 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { 887 size = stackSize + 2; 888 } else { 889 size = stackSize + 1; 890 } 891 // updates current and max stack sizes 892 if (size > maxStackSize) { 893 maxStackSize = size; 894 } 895 stackSize = size; 896 } 897 // adds the instruction to the bytecode of the method 898 int index = i.index; 899 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { 900 code.put12(20 /* LDC2_W */, index); 901 } else if (index >= 256) { 902 code.put12(19 /* LDC_W */, index); 903 } else { 904 code.put11(Opcodes.LDC, index); 905 } 906 } 907 908 public void visitIincInsn(final int var, final int increment) { 909 if (computeMaxs) { 910 // updates max locals only (no stack change) 911 int n = var + 1; 912 if (n > maxLocals) { 913 maxLocals = n; 914 } 915 } 916 // adds the instruction to the bytecode of the method 917 if ((var > 255) || (increment > 127) || (increment < -128)) { 918 code.putByte(196 /* WIDE */) 919 .put12(Opcodes.IINC, var) 920 .putShort(increment); 921 } else { 922 code.putByte(Opcodes.IINC).put11(var, increment); 923 } 924 } 925 926 public void visitTableSwitchInsn( 927 final int min, 928 final int max, 929 final Label dflt, 930 final Label labels[]) 931 { 932 if (computeMaxs) { 933 // updates current stack size (max stack size unchanged) 934 --stackSize; 935 // ends current block (with many new successors) 936 if (currentBlock != null) { 937 currentBlock.maxStackSize = maxStackSize; 938 addSuccessor(stackSize, dflt); 939 for (int i = 0; i < labels.length; ++i) { 940 addSuccessor(stackSize, labels[i]); 941 } 942 currentBlock = null; 943 } 944 } 945 // adds the instruction to the bytecode of the method 946 int source = code.length; 947 code.putByte(Opcodes.TABLESWITCH); 948 while (code.length % 4 != 0) { 949 code.putByte(0); 950 } 951 dflt.put(this, code, source, true); 952 code.putInt(min).putInt(max); 953 for (int i = 0; i < labels.length; ++i) { 954 labels[i].put(this, code, source, true); 955 } 956 } 957 958 public void visitLookupSwitchInsn( 959 final Label dflt, 960 final int keys[], 961 final Label labels[]) 962 { 963 if (computeMaxs) { 964 // updates current stack size (max stack size unchanged) 965 --stackSize; 966 // ends current block (with many new successors) 967 if (currentBlock != null) { 968 currentBlock.maxStackSize = maxStackSize; 969 addSuccessor(stackSize, dflt); 970 for (int i = 0; i < labels.length; ++i) { 971 addSuccessor(stackSize, labels[i]); 972 } 973 currentBlock = null; 974 } 975 } 976 // adds the instruction to the bytecode of the method 977 int source = code.length; 978 code.putByte(Opcodes.LOOKUPSWITCH); 979 while (code.length % 4 != 0) { 980 code.putByte(0); 981 } 982 dflt.put(this, code, source, true); 983 code.putInt(labels.length); 984 for (int i = 0; i < labels.length; ++i) { 985 code.putInt(keys[i]); 986 labels[i].put(this, code, source, true); 987 } 988 } 989 990 public void visitMultiANewArrayInsn(final String desc, final int dims) { 991 if (computeMaxs) { 992 // updates current stack size (max stack size unchanged because 993 // stack size variation always negative or null) 994 stackSize += 1 - dims; 995 } 996 // adds the instruction to the bytecode of the method 997 code.put12(Opcodes.MULTIANEWARRAY, cw.newClass(desc)).putByte(dims); 998 } 999 1000 public void visitTryCatchBlock( 1001 final Label start, 1002 final Label end, 1003 final Label handler, 1004 final String type) 1005 { 1006 if (computeMaxs) { 1007 // pushes handler block onto the stack of blocks to be visited 1008 if (!handler.pushed) { 1009 handler.beginStackSize = 1; 1010 handler.pushed = true; 1011 handler.next = blockStack; 1012 blockStack = handler; 1013 } 1014 } 1015 ++catchCount; 1016 Handler h = new Handler(); 1017 h.start = start; 1018 h.end = end; 1019 h.handler = handler; 1020 h.desc = type; 1021 h.type = type != null ? cw.newClass(type) : 0; 1022 if (lastHandler == null) { 1023 catchTable = h; 1024 } else { 1025 lastHandler.next = h; 1026 } 1027 lastHandler = h; 1028 } 1029 1030 public void visitLocalVariable( 1031 final String name, 1032 final String desc, 1033 final String signature, 1034 final Label start, 1035 final Label end, 1036 final int index) 1037 { 1038 if (signature != null) { 1039 if (localVarType == null) { 1040 localVarType = new ByteVector(); 1041 } 1042 ++localVarTypeCount; 1043 localVarType.putShort(start.position) 1044 .putShort(end.position - start.position) 1045 .putShort(cw.newUTF8(name)) 1046 .putShort(cw.newUTF8(signature)) 1047 .putShort(index); 1048 } 1049 if (localVar == null) { 1050 localVar = new ByteVector(); 1051 } 1052 ++localVarCount; 1053 localVar.putShort(start.position) 1054 .putShort(end.position - start.position) 1055 .putShort(cw.newUTF8(name)) 1056 .putShort(cw.newUTF8(desc)) 1057 .putShort(index); 1058 } 1059 1060 public void visitLineNumber(final int line, final Label start) { 1061 if (lineNumber == null) { 1062 lineNumber = new ByteVector(); 1063 } 1064 ++lineNumberCount; 1065 lineNumber.putShort(start.position); 1066 lineNumber.putShort(line); 1067 } 1068 1069 public void visitMaxs(final int maxStack, final int maxLocals) { 1070 if (computeMaxs) { 1071 // true (non relative) max stack size 1072 int max = 0; 1073 /* 1074 * control flow analysis algorithm: while the block stack is not 1075 * empty, pop a block from this stack, update the max stack size, 1076 * compute the true (non relative) begin stack size of the 1077 * successors of this block, and push these successors onto the 1078 * stack (unless they have already been pushed onto the stack). 1079 * Note: by hypothesis, the {@link Label#beginStackSize} of the 1080 * blocks in the block stack are the true (non relative) beginning 1081 * stack sizes of these blocks. 1082 */ 1083 Label stack = blockStack; 1084 while (stack != null) { 1085 // pops a block from the stack 1086 Label l = stack; 1087 stack = stack.next; 1088 // computes the true (non relative) max stack size of this block 1089 int start = l.beginStackSize; 1090 int blockMax = start + l.maxStackSize; 1091 // updates the global max stack size 1092 if (blockMax > max) { 1093 max = blockMax; 1094 } 1095 // analyses the successors of the block 1096 Edge b = l.successors; 1097 while (b != null) { 1098 l = b.successor; 1099 // if this successor has not already been pushed onto the 1100 // stack... 1101 if (!l.pushed) { 1102 // computes the true beginning stack size of this 1103 // successor block 1104 l.beginStackSize = start + b.stackSize; 1105 // pushes this successor onto the stack 1106 l.pushed = true; 1107 l.next = stack; 1108 stack = l; 1109 } 1110 b = b.next; 1111 } 1112 } 1113 this.maxStack = max; 1114 } else { 1115 this.maxStack = maxStack; 1116 this.maxLocals = maxLocals; 1117 } 1118 } 1119 1120 public void visitEnd() { 1121 } 1122 1123 // ------------------------------------------------------------------------ 1124 // Utility methods: control flow analysis algorithm 1125 // ------------------------------------------------------------------------ 1126 1127 /** 1128 * Computes the size of the arguments and of the return value of a method. 1129 * 1130 * @param desc the descriptor of a method. 1131 * @return the size of the arguments of the method (plus one for the 1132 * implicit this argument), argSize, and the size of its return 1133 * value, retSize, packed into a single int i = 1134 * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal 1135 * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>). 1136 */ 1137 private static int getArgumentsAndReturnSizes(final String desc) { 1138 int n = 1; 1139 int c = 1; 1140 while (true) { 1141 char car = desc.charAt(c++); 1142 if (car == ')') { 1143 car = desc.charAt(c); 1144 return n << 2 1145 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); 1146 } else if (car == 'L') { 1147 while (desc.charAt(c++) != ';') { 1148 } 1149 n += 1; 1150 } else if (car == '[') { 1151 while ((car = desc.charAt(c)) == '[') { 1152 ++c; 1153 } 1154 if (car == 'D' || car == 'J') { 1155 n -= 1; 1156 } 1157 } else if (car == 'D' || car == 'J') { 1158 n += 2; 1159 } else { 1160 n += 1; 1161 } 1162 } 1163 } 1164 1165 /** 1166 * Adds a successor to the {@link #currentBlock currentBlock} block. 1167 * 1168 * @param stackSize the current (relative) stack size in the current block. 1169 * @param successor the successor block to be added to the current block. 1170 */ 1171 private void addSuccessor(final int stackSize, final Label successor) { 1172 Edge b = new Edge(); 1173 // initializes the previous Edge object... 1174 b.stackSize = stackSize; 1175 b.successor = successor; 1176 // ...and adds it to the successor list of the currentBlock block 1177 b.next = currentBlock.successors; 1178 currentBlock.successors = b; 1179 } 1180 1181 // ------------------------------------------------------------------------ 1182 // Utility methods: dump bytecode array 1183 // ------------------------------------------------------------------------ 1184 1185 /** 1186 * Returns the size of the bytecode of this method. 1187 * 1188 * @return the size of the bytecode of this method. 1189 */ 1190 final int getSize() { 1191 if (classReaderOffset != 0) { 1192 return 6 + classReaderLength; 1193 } 1194 if (resize) { 1195 // replaces the temporary jump opcodes introduced by Label.resolve. 1196 resizeInstructions(new int[0], new int[0], 0); 1197 } 1198 int size = 8; 1199 if (code.length > 0) { 1200 cw.newUTF8("Code"); 1201 size += 18 + code.length + 8 * catchCount; 1202 if (localVar != null) { 1203 cw.newUTF8("LocalVariableTable"); 1204 size += 8 + localVar.length; 1205 } 1206 if (localVarType != null) { 1207 cw.newUTF8("LocalVariableTypeTable"); 1208 size += 8 + localVarType.length; 1209 } 1210 if (lineNumber != null) { 1211 cw.newUTF8("LineNumberTable"); 1212 size += 8 + lineNumber.length; 1213 } 1214 if (cattrs != null) { 1215 size += cattrs.getSize(cw, 1216 code.data, 1217 code.length, 1218 maxStack, 1219 maxLocals); 1220 } 1221 } 1222 if (exceptionCount > 0) { 1223 cw.newUTF8("Exceptions"); 1224 size += 8 + 2 * exceptionCount; 1225 } 1226 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1227 && (cw.version & 0xffff) < Opcodes.V1_5) 1228 { 1229 cw.newUTF8("Synthetic"); 1230 size += 6; 1231 } 1232 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1233 cw.newUTF8("Deprecated"); 1234 size += 6; 1235 } 1236 if (cw.version == Opcodes.V1_4) { 1237 if ((access & Opcodes.ACC_VARARGS) != 0) { 1238 cw.newUTF8("Varargs"); 1239 size += 6; 1240 } 1241 if ((access & Opcodes.ACC_BRIDGE) != 0) { 1242 cw.newUTF8("Bridge"); 1243 size += 6; 1244 } 1245 } 1246 if (signature != null) { 1247 cw.newUTF8("Signature"); 1248 cw.newUTF8(signature); 1249 size += 8; 1250 } 1251 if (annd != null) { 1252 cw.newUTF8("AnnotationDefault"); 1253 size += 6 + annd.length; 1254 } 1255 if (anns != null) { 1256 cw.newUTF8("RuntimeVisibleAnnotations"); 1257 size += 8 + anns.getSize(); 1258 } 1259 if (ianns != null) { 1260 cw.newUTF8("RuntimeInvisibleAnnotations"); 1261 size += 8 + ianns.getSize(); 1262 } 1263 if (panns != null) { 1264 cw.newUTF8("RuntimeVisibleParameterAnnotations"); 1265 size += 7 + 2 * panns.length; 1266 for (int i = panns.length - 1; i >= 0; --i) { 1267 size += panns[i] == null ? 0 : panns[i].getSize(); 1268 } 1269 } 1270 if (ipanns != null) { 1271 cw.newUTF8("RuntimeInvisibleParameterAnnotations"); 1272 size += 7 + 2 * ipanns.length; 1273 for (int i = ipanns.length - 1; i >= 0; --i) { 1274 size += ipanns[i] == null ? 0 : ipanns[i].getSize(); 1275 } 1276 } 1277 if (attrs != null) { 1278 size += attrs.getSize(cw, null, 0, -1, -1); 1279 } 1280 return size; 1281 } 1282 1283 /** 1284 * Puts the bytecode of this method in the given byte vector. 1285 * 1286 * @param out the byte vector into which the bytecode of this method must be 1287 * copied. 1288 */ 1289 final void put(final ByteVector out) { 1290 out.putShort(access).putShort(name).putShort(desc); 1291 if (classReaderOffset != 0) { 1292 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); 1293 return; 1294 } 1295 int attributeCount = 0; 1296 if (code.length > 0) { 1297 ++attributeCount; 1298 } 1299 if (exceptionCount > 0) { 1300 ++attributeCount; 1301 } 1302 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1303 && (cw.version & 0xffff) < Opcodes.V1_5) 1304 { 1305 ++attributeCount; 1306 } 1307 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1308 ++attributeCount; 1309 } 1310 if (cw.version == Opcodes.V1_4) { 1311 if ((access & Opcodes.ACC_VARARGS) != 0) { 1312 ++attributeCount; 1313 } 1314 if ((access & Opcodes.ACC_BRIDGE) != 0) { 1315 ++attributeCount; 1316 } 1317 } 1318 if (signature != null) { 1319 ++attributeCount; 1320 } 1321 if (annd != null) { 1322 ++attributeCount; 1323 } 1324 if (anns != null) { 1325 ++attributeCount; 1326 } 1327 if (ianns != null) { 1328 ++attributeCount; 1329 } 1330 if (panns != null) { 1331 ++attributeCount; 1332 } 1333 if (ipanns != null) { 1334 ++attributeCount; 1335 } 1336 if (attrs != null) { 1337 attributeCount += attrs.getCount(); 1338 } 1339 out.putShort(attributeCount); 1340 if (code.length > 0) { 1341 int size = 12 + code.length + 8 * catchCount; 1342 if (localVar != null) { 1343 size += 8 + localVar.length; 1344 } 1345 if (localVarType != null) { 1346 size += 8 + localVarType.length; 1347 } 1348 if (lineNumber != null) { 1349 size += 8 + lineNumber.length; 1350 } 1351 if (cattrs != null) { 1352 size += cattrs.getSize(cw, 1353 code.data, 1354 code.length, 1355 maxStack, 1356 maxLocals); 1357 } 1358 out.putShort(cw.newUTF8("Code")).putInt(size); 1359 out.putShort(maxStack).putShort(maxLocals); 1360 out.putInt(code.length).putByteArray(code.data, 0, code.length); 1361 out.putShort(catchCount); 1362 if (catchCount > 0) { 1363 Handler h = catchTable; 1364 while (h != null) { 1365 out.putShort(h.start.position) 1366 .putShort(h.end.position) 1367 .putShort(h.handler.position) 1368 .putShort(h.type); 1369 h = h.next; 1370 } 1371 } 1372 attributeCount = 0; 1373 if (localVar != null) { 1374 ++attributeCount; 1375 } 1376 if (localVarType != null) { 1377 ++attributeCount; 1378 } 1379 if (lineNumber != null) { 1380 ++attributeCount; 1381 } 1382 if (cattrs != null) { 1383 attributeCount += cattrs.getCount(); 1384 } 1385 out.putShort(attributeCount); 1386 if (localVar != null) { 1387 out.putShort(cw.newUTF8("LocalVariableTable")); 1388 out.putInt(localVar.length + 2).putShort(localVarCount); 1389 out.putByteArray(localVar.data, 0, localVar.length); 1390 } 1391 if (localVarType != null) { 1392 out.putShort(cw.newUTF8("LocalVariableTypeTable")); 1393 out.putInt(localVarType.length + 2).putShort(localVarTypeCount); 1394 out.putByteArray(localVarType.data, 0, localVarType.length); 1395 } 1396 if (lineNumber != null) { 1397 out.putShort(cw.newUTF8("LineNumberTable")); 1398 out.putInt(lineNumber.length + 2).putShort(lineNumberCount); 1399 out.putByteArray(lineNumber.data, 0, lineNumber.length); 1400 } 1401 if (cattrs != null) { 1402 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); 1403 } 1404 } 1405 if (exceptionCount > 0) { 1406 out.putShort(cw.newUTF8("Exceptions")) 1407 .putInt(2 * exceptionCount + 2); 1408 out.putShort(exceptionCount); 1409 for (int i = 0; i < exceptionCount; ++i) { 1410 out.putShort(exceptions[i]); 1411 } 1412 } 1413 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1414 && (cw.version & 0xffff) < Opcodes.V1_5) 1415 { 1416 out.putShort(cw.newUTF8("Synthetic")).putInt(0); 1417 } 1418 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1419 out.putShort(cw.newUTF8("Deprecated")).putInt(0); 1420 } 1421 if (cw.version == Opcodes.V1_4) { 1422 if ((access & Opcodes.ACC_VARARGS) != 0) { 1423 out.putShort(cw.newUTF8("Varargs")).putInt(0); 1424 } 1425 if ((access & Opcodes.ACC_BRIDGE) != 0) { 1426 out.putShort(cw.newUTF8("Bridge")).putInt(0); 1427 } 1428 } 1429 if (signature != null) { 1430 out.putShort(cw.newUTF8("Signature")) 1431 .putInt(2) 1432 .putShort(cw.newUTF8(signature)); 1433 } 1434 if (annd != null) { 1435 out.putShort(cw.newUTF8("AnnotationDefault")); 1436 out.putInt(annd.length); 1437 out.putByteArray(annd.data, 0, annd.length); 1438 } 1439 if (anns != null) { 1440 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); 1441 anns.put(out); 1442 } 1443 if (ianns != null) { 1444 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); 1445 ianns.put(out); 1446 } 1447 if (panns != null) { 1448 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); 1449 AnnotationWriter.put(panns, out); 1450 } 1451 if (ipanns != null) { 1452 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); 1453 AnnotationWriter.put(ipanns, out); 1454 } 1455 if (attrs != null) { 1456 attrs.put(cw, null, 0, -1, -1, out); 1457 } 1458 } 1459 1460 // ------------------------------------------------------------------------ 1461 // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) 1462 // ------------------------------------------------------------------------ 1463 1464 /** 1465 * Resizes the designated instructions, while keeping jump offsets and 1466 * instruction addresses consistent. This may require to resize other 1467 * existing instructions, or even to introduce new instructions: for 1468 * example, increasing the size of an instruction by 2 at the middle of a 1469 * method can increases the offset of an IFEQ instruction from 32766 to 1470 * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W 1471 * 32765. This, in turn, may require to increase the size of another jump 1472 * instruction, and so on... All these operations are handled automatically 1473 * by this method. <p> <i>This method must be called after all the method 1474 * that is being built has been visited</i>. In particular, the 1475 * {@link Label Label} objects used to construct the method are no longer 1476 * valid after this method has been called. 1477 * 1478 * @param indexes current positions of the instructions to be resized. Each 1479 * instruction must be designated by the index of its <i>last</i> 1480 * byte, plus one (or, in other words, by the index of the <i>first</i> 1481 * byte of the <i>next</i> instruction). 1482 * @param sizes the number of bytes to be <i>added</i> to the above 1483 * instructions. More precisely, for each i < <tt>len</tt>, 1484 * <tt>sizes</tt>[i] bytes will be added at the end of the 1485 * instruction designated by <tt>indexes</tt>[i] or, if 1486 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| 1487 * bytes of the instruction will be removed (the instruction size 1488 * <i>must not</i> become negative or null). The gaps introduced by 1489 * this method must be filled in "manually" in {@link #code code} 1490 * method. 1491 * @param len the number of instruction to be resized. Must be smaller than 1492 * or equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length. 1493 * @return the <tt>indexes</tt> array, which now contains the new 1494 * positions of the resized instructions (designated as above). 1495 */ 1496 private int[] resizeInstructions( 1497 final int[] indexes, 1498 final int[] sizes, 1499 final int len) 1500 { 1501 byte[] b = code.data; // bytecode of the method 1502 int u, v, label; // indexes in b 1503 int i, j; // loop indexes 1504 1505 /* 1506 * 1st step: As explained above, resizing an instruction may require to 1507 * resize another one, which may require to resize yet another one, and 1508 * so on. The first step of the algorithm consists in finding all the 1509 * instructions that need to be resized, without modifying the code. 1510 * This is done by the following "fix point" algorithm: 1511 * 1512 * Parse the code to find the jump instructions whose offset will need 1513 * more than 2 bytes to be stored (the future offset is computed from 1514 * the current offset and from the number of bytes that will be inserted 1515 * or removed between the source and target instructions). For each such 1516 * instruction, adds an entry in (a copy of) the indexes and sizes 1517 * arrays (if this has not already been done in a previous iteration!). 1518 * 1519 * If at least one entry has been added during the previous step, go 1520 * back to the beginning, otherwise stop. 1521 * 1522 * In fact the real algorithm is complicated by the fact that the size 1523 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their 1524 * position in the bytecode (because of padding). In order to ensure the 1525 * convergence of the algorithm, the number of bytes to be added or 1526 * removed from these instructions is over estimated during the previous 1527 * loop, and computed exactly only after the loop is finished (this 1528 * requires another pass to parse the bytecode of the method). 1529 */ 1530 int[] allIndexes = new int[len]; // copy of indexes 1531 int[] allSizes = new int[len]; // copy of sizes 1532 boolean[] resize; // instructions to be resized 1533 int newOffset; // future offset of a jump instruction 1534 1535 System.arraycopy(indexes, 0, allIndexes, 0, len); 1536 System.arraycopy(sizes, 0, allSizes, 0, len); 1537 resize = new boolean[code.length]; 1538 1539 // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done 1540 int state = 3; 1541 do { 1542 if (state == 3) { 1543 state = 2; 1544 } 1545 u = 0; 1546 while (u < b.length) { 1547 int opcode = b[u] & 0xFF; // opcode of current instruction 1548 int insert = 0; // bytes to be added after this instruction 1549 1550 switch (ClassWriter.TYPE[opcode]) { 1551 case ClassWriter.NOARG_INSN: 1552 case ClassWriter.IMPLVAR_INSN: 1553 u += 1; 1554 break; 1555 case ClassWriter.LABEL_INSN: 1556 if (opcode > 201) { 1557 // converts temporary opcodes 202 to 217, 218 and 1558 // 219 to IFEQ ... JSR (inclusive), IFNULL and 1559 // IFNONNULL 1560 opcode = opcode < 218 ? opcode - 49 : opcode - 20; 1561 label = u + readUnsignedShort(b, u + 1); 1562 } else { 1563 label = u + readShort(b, u + 1); 1564 } 1565 newOffset = getNewOffset(allIndexes, allSizes, u, label); 1566 if (newOffset < Short.MIN_VALUE 1567 || newOffset > Short.MAX_VALUE) 1568 { 1569 if (!resize[u]) { 1570 if (opcode == Opcodes.GOTO 1571 || opcode == Opcodes.JSR) 1572 { 1573 // two additional bytes will be required to 1574 // replace this GOTO or JSR instruction with 1575 // a GOTO_W or a JSR_W 1576 insert = 2; 1577 } else { 1578 // five additional bytes will be required to 1579 // replace this IFxxx <l> instruction with 1580 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx 1581 // is the "opposite" opcode of IFxxx (i.e., 1582 // IFNE for IFEQ) and where <l'> designates 1583 // the instruction just after the GOTO_W. 1584 insert = 5; 1585 } 1586 resize[u] = true; 1587 } 1588 } 1589 u += 3; 1590 break; 1591 case ClassWriter.LABELW_INSN: 1592 u += 5; 1593 break; 1594 case ClassWriter.TABL_INSN: 1595 if (state == 1) { 1596 // true number of bytes to be added (or removed) 1597 // from this instruction = (future number of padding 1598 // bytes - current number of padding byte) - 1599 // previously over estimated variation = 1600 // = ((3 - newOffset%4) - (3 - u%4)) - u%4 1601 // = (-newOffset%4 + u%4) - u%4 1602 // = -(newOffset & 3) 1603 newOffset = getNewOffset(allIndexes, allSizes, 0, u); 1604 insert = -(newOffset & 3); 1605 } else if (!resize[u]) { 1606 // over estimation of the number of bytes to be 1607 // added to this instruction = 3 - current number 1608 // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 1609 insert = u & 3; 1610 resize[u] = true; 1611 } 1612 // skips instruction 1613 u = u + 4 - (u & 3); 1614 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; 1615 break; 1616 case ClassWriter.LOOK_INSN: 1617 if (state == 1) { 1618 // like TABL_INSN 1619 newOffset = getNewOffset(allIndexes, allSizes, 0, u); 1620 insert = -(newOffset & 3); 1621 } else if (!resize[u]) { 1622 // like TABL_INSN 1623 insert = u & 3; 1624 resize[u] = true; 1625 } 1626 // skips instruction 1627 u = u + 4 - (u & 3); 1628 u += 8 * readInt(b, u + 4) + 8; 1629 break; 1630 case ClassWriter.WIDE_INSN: 1631 opcode = b[u + 1] & 0xFF; 1632 if (opcode == Opcodes.IINC) { 1633 u += 6; 1634 } else { 1635 u += 4; 1636 } 1637 break; 1638 case ClassWriter.VAR_INSN: 1639 case ClassWriter.SBYTE_INSN: 1640 case ClassWriter.LDC_INSN: 1641 u += 2; 1642 break; 1643 case ClassWriter.SHORT_INSN: 1644 case ClassWriter.LDCW_INSN: 1645 case ClassWriter.FIELDORMETH_INSN: 1646 case ClassWriter.TYPE_INSN: 1647 case ClassWriter.IINC_INSN: 1648 u += 3; 1649 break; 1650 case ClassWriter.ITFMETH_INSN: 1651 u += 5; 1652 break; 1653 // case ClassWriter.MANA_INSN: 1654 default: 1655 u += 4; 1656 break; 1657 } 1658 if (insert != 0) { 1659 // adds a new (u, insert) entry in the allIndexes and 1660 // allSizes arrays 1661 int[] newIndexes = new int[allIndexes.length + 1]; 1662 int[] newSizes = new int[allSizes.length + 1]; 1663 System.arraycopy(allIndexes, 1664 0, 1665 newIndexes, 1666 0, 1667 allIndexes.length); 1668 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); 1669 newIndexes[allIndexes.length] = u; 1670 newSizes[allSizes.length] = insert; 1671 allIndexes = newIndexes; 1672 allSizes = newSizes; 1673 if (insert > 0) { 1674 state = 3; 1675 } 1676 } 1677 } 1678 if (state < 3) { 1679 --state; 1680 } 1681 } while (state != 0); 1682 1683 // 2nd step: 1684 // copies the bytecode of the method into a new bytevector, updates the 1685 // offsets, and inserts (or removes) bytes as requested. 1686 1687 ByteVector newCode = new ByteVector(code.length); 1688 1689 u = 0; 1690 while (u < code.length) { 1691 for (i = allIndexes.length - 1; i >= 0; --i) { 1692 if (allIndexes[i] == u) { 1693 if (i < len) { 1694 if (sizes[i] > 0) { 1695 newCode.putByteArray(null, 0, sizes[i]); 1696 } else { 1697 newCode.length += sizes[i]; 1698 } 1699 indexes[i] = newCode.length; 1700 } 1701 } 1702 } 1703 int opcode = b[u] & 0xFF; 1704 switch (ClassWriter.TYPE[opcode]) { 1705 case ClassWriter.NOARG_INSN: 1706 case ClassWriter.IMPLVAR_INSN: 1707 newCode.putByte(opcode); 1708 u += 1; 1709 break; 1710 case ClassWriter.LABEL_INSN: 1711 if (opcode > 201) { 1712 // changes temporary opcodes 202 to 217 (inclusive), 218 1713 // and 219 to IFEQ ... JSR (inclusive), IFNULL and 1714 // IFNONNULL 1715 opcode = opcode < 218 ? opcode - 49 : opcode - 20; 1716 label = u + readUnsignedShort(b, u + 1); 1717 } else { 1718 label = u + readShort(b, u + 1); 1719 } 1720 newOffset = getNewOffset(allIndexes, allSizes, u, label); 1721 if (resize[u]) { 1722 // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx 1723 // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is 1724 // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) 1725 // and where <l'> designates the instruction just after 1726 // the GOTO_W. 1727 if (opcode == Opcodes.GOTO) { 1728 newCode.putByte(200); // GOTO_W 1729 } else if (opcode == Opcodes.JSR) { 1730 newCode.putByte(201); // JSR_W 1731 } else { 1732 newCode.putByte(opcode <= 166 1733 ? ((opcode + 1) ^ 1) - 1 1734 : opcode ^ 1); 1735 newCode.putShort(8); // jump offset 1736 newCode.putByte(200); // GOTO_W 1737 // newOffset now computed from start of GOTO_W 1738 newOffset -= 3; 1739 } 1740 newCode.putInt(newOffset); 1741 } else { 1742 newCode.putByte(opcode); 1743 newCode.putShort(newOffset); 1744 } 1745 u += 3; 1746 break; 1747 case ClassWriter.LABELW_INSN: 1748 label = u + readInt(b, u + 1); 1749 newOffset = getNewOffset(allIndexes, allSizes, u, label); 1750 newCode.putByte(opcode); 1751 newCode.putInt(newOffset); 1752 u += 5; 1753 break; 1754 case ClassWriter.TABL_INSN: 1755 // skips 0 to 3 padding bytes 1756 v = u; 1757 u = u + 4 - (v & 3); 1758 // reads and copies instruction 1759 newCode.putByte(Opcodes.TABLESWITCH); 1760 while (newCode.length % 4 != 0) { 1761 newCode.putByte(0); 1762 } 1763 label = v + readInt(b, u); 1764 u += 4; 1765 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1766 newCode.putInt(newOffset); 1767 j = readInt(b, u); 1768 u += 4; 1769 newCode.putInt(j); 1770 j = readInt(b, u) - j + 1; 1771 u += 4; 1772 newCode.putInt(readInt(b, u - 4)); 1773 for (; j > 0; --j) { 1774 label = v + readInt(b, u); 1775 u += 4; 1776 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1777 newCode.putInt(newOffset); 1778 } 1779 break; 1780 case ClassWriter.LOOK_INSN: 1781 // skips 0 to 3 padding bytes 1782 v = u; 1783 u = u + 4 - (v & 3); 1784 // reads and copies instruction 1785 newCode.putByte(Opcodes.LOOKUPSWITCH); 1786 while (newCode.length % 4 != 0) { 1787 newCode.putByte(0); 1788 } 1789 label = v + readInt(b, u); 1790 u += 4; 1791 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1792 newCode.putInt(newOffset); 1793 j = readInt(b, u); 1794 u += 4; 1795 newCode.putInt(j); 1796 for (; j > 0; --j) { 1797 newCode.putInt(readInt(b, u)); 1798 u += 4; 1799 label = v + readInt(b, u); 1800 u += 4; 1801 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1802 newCode.putInt(newOffset); 1803 } 1804 break; 1805 case ClassWriter.WIDE_INSN: 1806 opcode = b[u + 1] & 0xFF; 1807 if (opcode == Opcodes.IINC) { 1808 newCode.putByteArray(b, u, 6); 1809 u += 6; 1810 } else { 1811 newCode.putByteArray(b, u, 4); 1812 u += 4; 1813 } 1814 break; 1815 case ClassWriter.VAR_INSN: 1816 case ClassWriter.SBYTE_INSN: 1817 case ClassWriter.LDC_INSN: 1818 newCode.putByteArray(b, u, 2); 1819 u += 2; 1820 break; 1821 case ClassWriter.SHORT_INSN: 1822 case ClassWriter.LDCW_INSN: 1823 case ClassWriter.FIELDORMETH_INSN: 1824 case ClassWriter.TYPE_INSN: 1825 case ClassWriter.IINC_INSN: 1826 newCode.putByteArray(b, u, 3); 1827 u += 3; 1828 break; 1829 case ClassWriter.ITFMETH_INSN: 1830 newCode.putByteArray(b, u, 5); 1831 u += 5; 1832 break; 1833 // case MANA_INSN: 1834 default: 1835 newCode.putByteArray(b, u, 4); 1836 u += 4; 1837 break; 1838 } 1839 } 1840 1841 // updates the exception handler block labels 1842 Handler h = catchTable; 1843 while (h != null) { 1844 getNewOffset(allIndexes, allSizes, h.start); 1845 getNewOffset(allIndexes, allSizes, h.end); 1846 getNewOffset(allIndexes, allSizes, h.handler); 1847 h = h.next; 1848 } 1849 for (i = 0; i < 2; ++i) { 1850 ByteVector bv = i == 0 ? localVar : localVarType; 1851 if (bv != null) { 1852 b = bv.data; 1853 u = 0; 1854 while (u < bv.length) { 1855 label = readUnsignedShort(b, u); 1856 newOffset = getNewOffset(allIndexes, allSizes, 0, label); 1857 writeShort(b, u, newOffset); 1858 label += readUnsignedShort(b, u + 2); 1859 newOffset = getNewOffset(allIndexes, allSizes, 0, label) 1860 - newOffset; 1861 writeShort(b, u + 2, newOffset); 1862 u += 10; 1863 } 1864 } 1865 } 1866 if (lineNumber != null) { 1867 b = lineNumber.data; 1868 u = 0; 1869 while (u < lineNumber.length) { 1870 writeShort(b, u, getNewOffset(allIndexes, 1871 allSizes, 1872 0, 1873 readUnsignedShort(b, u))); 1874 u += 4; 1875 } 1876 } 1877 // updates the labels of the other attributes 1878 while (cattrs != null) { 1879 Label[] labels = cattrs.getLabels(); 1880 if (labels != null) { 1881 for (i = labels.length - 1; i >= 0; --i) { 1882 if (!labels[i].resized) { 1883 labels[i].position = getNewOffset(allIndexes, 1884 allSizes, 1885 0, 1886 labels[i].position); 1887 labels[i].resized = true; 1888 } 1889 } 1890 } 1891 } 1892 1893 // replaces old bytecodes with new ones 1894 code = newCode; 1895 1896 // returns the positions of the resized instructions 1897 return indexes; 1898 } 1899 1900 /** 1901 * Reads an unsigned short value in the given byte array. 1902 * 1903 * @param b a byte array. 1904 * @param index the start index of the value to be read. 1905 * @return the read value. 1906 */ 1907 static int readUnsignedShort(final byte[] b, final int index) { 1908 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); 1909 } 1910 1911 /** 1912 * Reads a signed short value in the given byte array. 1913 * 1914 * @param b a byte array. 1915 * @param index the start index of the value to be read. 1916 * @return the read value. 1917 */ 1918 static short readShort(final byte[] b, final int index) { 1919 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); 1920 } 1921 1922 /** 1923 * Reads a signed int value in the given byte array. 1924 * 1925 * @param b a byte array. 1926 * @param index the start index of the value to be read. 1927 * @return the read value. 1928 */ 1929 static int readInt(final byte[] b, final int index) { 1930 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) 1931 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); 1932 } 1933 1934 /** 1935 * Writes a short value in the given byte array. 1936 * 1937 * @param b a byte array. 1938 * @param index where the first byte of the short value must be written. 1939 * @param s the value to be written in the given byte array. 1940 */ 1941 static void writeShort(final byte[] b, final int index, final int s) { 1942 b[index] = (byte) (s >>> 8); 1943 b[index + 1] = (byte) s; 1944 } 1945 1946 /** 1947 * Computes the future value of a bytecode offset. <p> Note: it is possible 1948 * to have several entries for the same instruction in the <tt>indexes</tt> 1949 * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b') 1950 * are equivalent to a single entry (index=a,size=b+b'). 1951 * 1952 * @param indexes current positions of the instructions to be resized. Each 1953 * instruction must be designated by the index of its <i>last</i> 1954 * byte, plus one (or, in other words, by the index of the <i>first</i> 1955 * byte of the <i>next</i> instruction). 1956 * @param sizes the number of bytes to be <i>added</i> to the above 1957 * instructions. More precisely, for each i < <tt>len</tt>, 1958 * <tt>sizes</tt>[i] bytes will be added at the end of the 1959 * instruction designated by <tt>indexes</tt>[i] or, if 1960 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| 1961 * bytes of the instruction will be removed (the instruction size 1962 * <i>must not</i> become negative or null). 1963 * @param begin index of the first byte of the source instruction. 1964 * @param end index of the first byte of the target instruction. 1965 * @return the future value of the given bytecode offset. 1966 */ 1967 static int getNewOffset( 1968 final int[] indexes, 1969 final int[] sizes, 1970 final int begin, 1971 final int end) 1972 { 1973 int offset = end - begin; 1974 for (int i = 0; i < indexes.length; ++i) { 1975 if (begin < indexes[i] && indexes[i] <= end) { 1976 // forward jump 1977 offset += sizes[i]; 1978 } else if (end < indexes[i] && indexes[i] <= begin) { 1979 // backward jump 1980 offset -= sizes[i]; 1981 } 1982 } 1983 return offset; 1984 } 1985 1986 /** 1987 * Updates the offset of the given label. 1988 * 1989 * @param indexes current positions of the instructions to be resized. Each 1990 * instruction must be designated by the index of its <i>last</i> 1991 * byte, plus one (or, in other words, by the index of the <i>first</i> 1992 * byte of the <i>next</i> instruction). 1993 * @param sizes the number of bytes to be <i>added</i> to the above 1994 * instructions. More precisely, for each i < <tt>len</tt>, 1995 * <tt>sizes</tt>[i] bytes will be added at the end of the 1996 * instruction designated by <tt>indexes</tt>[i] or, if 1997 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>| 1998 * bytes of the instruction will be removed (the instruction size 1999 * <i>must not</i> become negative or null). 2000 * @param label the label whose offset must be updated. 2001 */ 2002 static void getNewOffset( 2003 final int[] indexes, 2004 final int[] sizes, 2005 final Label label) 2006 { 2007 if (!label.resized) { 2008 label.position = getNewOffset(indexes, sizes, 0, label.position); 2009 label.resized = true; 2010 } 2011 } 2012} 2013