PageRenderTime 489ms CodeModel.GetById 121ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-3-pre5/org/objectweb/asm/CodeWriter.java

#
Java | 1766 lines | 968 code | 124 blank | 674 comment | 341 complexity | 971fe39529fb2211270217540e882e0a MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/***
   2 * ASM: a very small and fast Java bytecode manipulation framework
   3 * Copyright (C) 2000 INRIA, France Telecom
   4 * Copyright (C) 2002 France Telecom
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 *
  20 * Contact: Eric.Bruneton@rd.francetelecom.com
  21 *
  22 * Author: Eric Bruneton
  23 */
  24
  25package org.objectweb.asm;
  26
  27/**
  28 * A {@link CodeVisitor CodeVisitor} that generates Java bytecode instructions.
  29 * Each visit method of this class appends the bytecode corresponding to the
  30 * visited instruction to a byte vector, in the order these methods are called.
  31 */
  32
  33public class CodeWriter implements CodeVisitor {
  34
  35  /**
  36   * <tt>true</tt> if preconditions must be checked at runtime or not.
  37   */
  38
  39  final static boolean CHECK = false;
  40
  41  /**
  42   * Next code writer (see {@link ClassWriter#firstMethod firstMethod}).
  43   */
  44
  45  CodeWriter next;
  46
  47  /**
  48   * The class writer to which this method must be added.
  49   */
  50
  51  private ClassWriter cw;
  52
  53  /**
  54   * The constant pool item that contains the name of this method.
  55   */
  56
  57  private Item name;
  58
  59  /**
  60   * The constant pool item that contains the descriptor of this method.
  61   */
  62
  63  private Item desc;
  64
  65  /**
  66   * Access flags of this method.
  67   */
  68
  69  private int access;
  70
  71  /**
  72   * Maximum stack size of this method.
  73   */
  74
  75  private int maxStack;
  76
  77  /**
  78   * Maximum number of local variables for this method.
  79   */
  80
  81  private int maxLocals;
  82
  83  /**
  84   * The bytecode of this method.
  85   */
  86
  87  private ByteVector code = new ByteVector();
  88
  89  /**
  90   * Number of entries in the catch table of this method.
  91   */
  92
  93  private int catchCount;
  94
  95  /**
  96   * The catch table of this method.
  97   */
  98
  99  private ByteVector catchTable;
 100
 101  /**
 102   * Number of exceptions that can be thrown by this method.
 103   */
 104
 105  private int exceptionCount;
 106
 107  /**
 108   * The exceptions that can be thrown by this method. More
 109   * precisely, this array contains the indexes of the constant pool items
 110   * that contain the internal names of these exception classes.
 111   */
 112
 113  private int[] exceptions;
 114
 115  /**
 116   * Number of entries in the LocalVariableTable attribute.
 117   */
 118
 119  private int localVarCount;
 120
 121  /**
 122   * The LocalVariableTable attribute.
 123   */
 124
 125  private ByteVector localVar;
 126
 127  /**
 128   * Number of entries in the LineNumberTable attribute.
 129   */
 130
 131  private int lineNumberCount;
 132
 133  /**
 134   * The LineNumberTable attribute.
 135   */
 136
 137  private ByteVector lineNumber;
 138
 139  /**
 140   * Indicates if some jump instructions are too small and need to be resized.
 141   */
 142
 143  private boolean resize;
 144
 145  // --------------------------------------------------------------------------
 146  // Fields for the control flow graph analysis algorithm (used to compute the
 147  // maximum stack size). A control flow graph contains one node per "basic
 148  // block", and one edge per "jump" from one basic block to another. Each node
 149  // (i.e., each basic block) is represented by the Label object that
 150  // corresponds to the first instruction of this basic block. Each node also
 151  // stores the list of its successors in the graph, as a linked list of Edge
 152  // objects.
 153  // --------------------------------------------------------------------------
 154
 155  /**
 156   * <tt>true</tt> if the maximum stack size and number of local variables must
 157   * be automatically computed.
 158   */
 159
 160  private final boolean computeMaxs;
 161
 162  /**
 163   * The (relative) stack size after the last visited instruction. This size is
 164   * relative to the beginning of the current basic block, i.e., the true stack
 165   * size after the last visited instruction is equal to the {@link
 166   * Label#beginStackSize beginStackSize} of the current basic block plus
 167   * <tt>stackSize</tt>.
 168   */
 169
 170  private int stackSize;
 171
 172  /**
 173   * The (relative) maximum stack size after the last visited instruction. This
 174   * size is relative to the beginning of the current basic block, i.e., the
 175   * true maximum stack size after the last visited instruction is equal to the
 176   * {@link Label#beginStackSize beginStackSize} of the current basic block plus
 177   * <tt>stackSize</tt>.
 178   */
 179
 180  private int maxStackSize;
 181
 182  /**
 183   * The current basic block. This block is the basic block to which the next
 184   * instruction to be visited must be added.
 185   */
 186
 187  private Label currentBlock;
 188
 189  /**
 190   * The basic block stack used by the control flow analysis algorithm. This
 191   * stack is represented by a linked list of {@link Label Label} objects,
 192   * linked to each other by their {@link Label#next} field. This stack must
 193   * not be confused with the JVM stack used to execute the JVM instructions!
 194   */
 195
 196  private Label blockStack;
 197
 198  /**
 199   * The stack size variation corresponding to each JVM instruction. This stack
 200   * variation is equal to the size of the values produced by an instruction,
 201   * minus the size of the values consumed by this instruction.
 202   */
 203
 204  private final static int[] SIZE;
 205
 206  // --------------------------------------------------------------------------
 207  // Fields to optimize the creation of {@link Edge Edge} objects by using a
 208  // pool of reusable objects. The (shared) pool is a linked list of Edge
 209  // objects, linked to each other by their {@link Edge#poolNext} field. Each
 210  // time a CodeWriter needs to allocate an Edge, it removes the first Edge
 211  // of the pool and adds it to a private list of Edge objects. After the end
 212  // of the control flow analysis algorithm, the Edge objects in the private
 213  // list of the CodeWriter are added back to the pool (by appending this
 214  // private list to the pool list; in order to do this in constant time, both
 215  // head and tail of the private list are stored in this CodeWriter).
 216  // --------------------------------------------------------------------------
 217
 218  /**
 219   * The head of the list of {@link Edge Edge} objects used by this {@link
 220   * CodeWriter CodeWriter}. These objects, linked to each other by their
 221   * {@link Edge#poolNext} field, are added back to the shared pool at the
 222   * end of the control flow analysis algorithm.
 223   */
 224
 225  private Edge head;
 226
 227  /**
 228   * The tail of the list of {@link Edge Edge} objects used by this {@link
 229   * CodeWriter CodeWriter}. These objects, linked to each other by their
 230   * {@link Edge#poolNext} field, are added back to the shared pool at the
 231   * end of the control flow analysis algorithm.
 232   */
 233
 234  private Edge tail;
 235
 236  /**
 237   * The shared pool of {@link Edge Edge} objects. This pool is a linked list
 238   * of Edge objects, linked to each other by their {@link Edge#poolNext} field.
 239   */
 240
 241  private static Edge pool;
 242
 243  // --------------------------------------------------------------------------
 244  // Static initializer
 245  // --------------------------------------------------------------------------
 246
 247  /**
 248   * Computes the stack size variation corresponding to each JVM instruction.
 249   */
 250
 251  static {
 252    int i;
 253    int[] b = new int[202];
 254    String s =
 255      "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDDCDCDEEEEEEEEE" +
 256      "EEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCDCDCEEEEDDDDDDDCDCDCEFEF" +
 257      "DDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFEDDDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
 258    for (i = 0; i < b.length; ++i) {
 259      b[i] = s.charAt(i) - 'E';
 260    }
 261    SIZE = b;
 262
 263    /* code to generate the above string
 264
 265    int NA = 0; // not applicable (unused opcode or variable size opcode)
 266
 267    b = new int[] {
 268      0,  //NOP,             // visitInsn
 269      1,  //ACONST_NULL,     // -
 270      1,  //ICONST_M1,       // -
 271      1,  //ICONST_0,        // -
 272      1,  //ICONST_1,        // -
 273      1,  //ICONST_2,        // -
 274      1,  //ICONST_3,        // -
 275      1,  //ICONST_4,        // -
 276      1,  //ICONST_5,        // -
 277      2,  //LCONST_0,        // -
 278      2,  //LCONST_1,        // -
 279      1,  //FCONST_0,        // -
 280      1,  //FCONST_1,        // -
 281      1,  //FCONST_2,        // -
 282      2,  //DCONST_0,        // -
 283      2,  //DCONST_1,        // -
 284      1,  //BIPUSH,          // visitIntInsn
 285      1,  //SIPUSH,          // -
 286      1,  //LDC,             // visitLdcInsn
 287      NA, //LDC_W,           // -
 288      NA, //LDC2_W,          // -
 289      1,  //ILOAD,           // visitVarInsn
 290      2,  //LLOAD,           // -
 291      1,  //FLOAD,           // -
 292      2,  //DLOAD,           // -
 293      1,  //ALOAD,           // -
 294      NA, //ILOAD_0,         // -
 295      NA, //ILOAD_1,         // -
 296      NA, //ILOAD_2,         // -
 297      NA, //ILOAD_3,         // -
 298      NA, //LLOAD_0,         // -
 299      NA, //LLOAD_1,         // -
 300      NA, //LLOAD_2,         // -
 301      NA, //LLOAD_3,         // -
 302      NA, //FLOAD_0,         // -
 303      NA, //FLOAD_1,         // -
 304      NA, //FLOAD_2,         // -
 305      NA, //FLOAD_3,         // -
 306      NA, //DLOAD_0,         // -
 307      NA, //DLOAD_1,         // -
 308      NA, //DLOAD_2,         // -
 309      NA, //DLOAD_3,         // -
 310      NA, //ALOAD_0,         // -
 311      NA, //ALOAD_1,         // -
 312      NA, //ALOAD_2,         // -
 313      NA, //ALOAD_3,         // -
 314      -1, //IALOAD,          // visitInsn
 315      0,  //LALOAD,          // -
 316      -1, //FALOAD,          // -
 317      0,  //DALOAD,          // -
 318      -1, //AALOAD,          // -
 319      -1, //BALOAD,          // -
 320      -1, //CALOAD,          // -
 321      -1, //SALOAD,          // -
 322      -1, //ISTORE,          // visitVarInsn
 323      -2, //LSTORE,          // -
 324      -1, //FSTORE,          // -
 325      -2, //DSTORE,          // -
 326      -1, //ASTORE,          // -
 327      NA, //ISTORE_0,        // -
 328      NA, //ISTORE_1,        // -
 329      NA, //ISTORE_2,        // -
 330      NA, //ISTORE_3,        // -
 331      NA, //LSTORE_0,        // -
 332      NA, //LSTORE_1,        // -
 333      NA, //LSTORE_2,        // -
 334      NA, //LSTORE_3,        // -
 335      NA, //FSTORE_0,        // -
 336      NA, //FSTORE_1,        // -
 337      NA, //FSTORE_2,        // -
 338      NA, //FSTORE_3,        // -
 339      NA, //DSTORE_0,        // -
 340      NA, //DSTORE_1,        // -
 341      NA, //DSTORE_2,        // -
 342      NA, //DSTORE_3,        // -
 343      NA, //ASTORE_0,        // -
 344      NA, //ASTORE_1,        // -
 345      NA, //ASTORE_2,        // -
 346      NA, //ASTORE_3,        // -
 347      -3, //IASTORE,         // visitInsn
 348      -4, //LASTORE,         // -
 349      -3, //FASTORE,         // -
 350      -4, //DASTORE,         // -
 351      -3, //AASTORE,         // -
 352      -3, //BASTORE,         // -
 353      -3, //CASTORE,         // -
 354      -3, //SASTORE,         // -
 355      -1, //POP,             // -
 356      -2, //POP2,            // -
 357      1,  //DUP,             // -
 358      1,  //DUP_X1,          // -
 359      1,  //DUP_X2,          // -
 360      2,  //DUP2,            // -
 361      2,  //DUP2_X1,         // -
 362      2,  //DUP2_X2,         // -
 363      0,  //SWAP,            // -
 364      -1, //IADD,            // -
 365      -2, //LADD,            // -
 366      -1, //FADD,            // -
 367      -2, //DADD,            // -
 368      -1, //ISUB,            // -
 369      -2, //LSUB,            // -
 370      -1, //FSUB,            // -
 371      -2, //DSUB,            // -
 372      -1, //IMUL,            // -
 373      -2, //LMUL,            // -
 374      -1, //FMUL,            // -
 375      -2, //DMUL,            // -
 376      -1, //IDIV,            // -
 377      -2, //LDIV,            // -
 378      -1, //FDIV,            // -
 379      -2, //DDIV,            // -
 380      -1, //IREM,            // -
 381      -2, //LREM,            // -
 382      -1, //FREM,            // -
 383      -2, //DREM,            // -
 384      0,  //INEG,            // -
 385      0,  //LNEG,            // -
 386      0,  //FNEG,            // -
 387      0,  //DNEG,            // -
 388      -1, //ISHL,            // -
 389      -1, //LSHL,            // -
 390      -1, //ISHR,            // -
 391      -1, //LSHR,            // -
 392      -1, //IUSHR,           // -
 393      -1, //LUSHR,           // -
 394      -1, //IAND,            // -
 395      -2, //LAND,            // -
 396      -1, //IOR,             // -
 397      -2, //LOR,             // -
 398      -1, //IXOR,            // -
 399      -2, //LXOR,            // -
 400      0,  //IINC,            // visitIincInsn
 401      1,  //I2L,             // visitInsn
 402      0,  //I2F,             // -
 403      1,  //I2D,             // -
 404      -1, //L2I,             // -
 405      -1, //L2F,             // -
 406      0,  //L2D,             // -
 407      0,  //F2I,             // -
 408      1,  //F2L,             // -
 409      1,  //F2D,             // -
 410      -1, //D2I,             // -
 411      0,  //D2L,             // -
 412      -1, //D2F,             // -
 413      0,  //I2B,             // -
 414      0,  //I2C,             // -
 415      0,  //I2S,             // -
 416      -3, //LCMP,            // -
 417      -1, //FCMPL,           // -
 418      -1, //FCMPG,           // -
 419      -3, //DCMPL,           // -
 420      -3, //DCMPG,           // -
 421      -1, //IFEQ,            // visitJumpInsn
 422      -1, //IFNE,            // -
 423      -1, //IFLT,            // -
 424      -1, //IFGE,            // -
 425      -1, //IFGT,            // -
 426      -1, //IFLE,            // -
 427      -2, //IF_ICMPEQ,       // -
 428      -2, //IF_ICMPNE,       // -
 429      -2, //IF_ICMPLT,       // -
 430      -2, //IF_ICMPGE,       // -
 431      -2, //IF_ICMPGT,       // -
 432      -2, //IF_ICMPLE,       // -
 433      -2, //IF_ACMPEQ,       // -
 434      -2, //IF_ACMPNE,       // -
 435      0,  //GOTO,            // -
 436      1,  //JSR,             // -
 437      0,  //RET,             // visitVarInsn
 438      -1, //TABLESWITCH,     // visiTableSwitchInsn
 439      -1, //LOOKUPSWITCH,    // visitLookupSwitch
 440      -1, //IRETURN,         // visitInsn
 441      -2, //LRETURN,         // -
 442      -1, //FRETURN,         // -
 443      -2, //DRETURN,         // -
 444      -1, //ARETURN,         // -
 445      0,  //RETURN,          // -
 446      NA, //GETSTATIC,       // visitFieldInsn
 447      NA, //PUTSTATIC,       // -
 448      NA, //GETFIELD,        // -
 449      NA, //PUTFIELD,        // -
 450      NA, //INVOKEVIRTUAL,   // visitMethodInsn
 451      NA, //INVOKESPECIAL,   // -
 452      NA, //INVOKESTATIC,    // -
 453      NA, //INVOKEINTERFACE, // -
 454      NA, //UNUSED,          // NOT VISITED
 455      1,  //NEW,             // visitTypeInsn
 456      0,  //NEWARRAY,        // visitIntInsn
 457      0,  //ANEWARRAY,       // visitTypeInsn
 458      0,  //ARRAYLENGTH,     // visitInsn
 459      NA, //ATHROW,          // -
 460      0,  //CHECKCAST,       // visitTypeInsn
 461      0,  //INSTANCEOF,      // -
 462      -1, //MONITORENTER,    // visitInsn
 463      -1, //MONITOREXIT,     // -
 464      NA, //WIDE,            // NOT VISITED
 465      NA, //MULTIANEWARRAY,  // visitMultiANewArrayInsn
 466      -1, //IFNULL,          // visitJumpInsn
 467      -1, //IFNONNULL,       // -
 468      NA, //GOTO_W,          // -
 469      NA, //JSR_W,           // -
 470    };
 471    for (i = 0; i < b.length; ++i) {
 472      System.err.print((char)('E' + b[i]));
 473    }
 474    System.err.println();
 475    */
 476  }
 477
 478  // --------------------------------------------------------------------------
 479  // Constructor
 480  // --------------------------------------------------------------------------
 481
 482  /**
 483   * Constructs a CodeWriter.
 484   *
 485   * @param cw the class writer in which the method must be added.
 486   * @param computeMaxs <tt>true</tt> if the maximum stack size and number of
 487   *      local variables must be automatically computed.
 488   */
 489
 490  protected CodeWriter (final ClassWriter cw, final boolean computeMaxs) {
 491    if (cw.firstMethod == null) {
 492      cw.firstMethod = this;
 493      cw.lastMethod = this;
 494    } else {
 495      cw.lastMethod.next = this;
 496      cw.lastMethod = this;
 497    }
 498    this.cw = cw;
 499    this.computeMaxs = computeMaxs;
 500    if (computeMaxs) {
 501      // pushes the first block onto the stack of blocks to be visited
 502      currentBlock = new Label();
 503      currentBlock.pushed = true;
 504      blockStack = currentBlock;
 505    }
 506  }
 507
 508  /**
 509   * Initializes this CodeWriter to define the bytecode of the specified method.
 510   *
 511   * @param access the method's access flags (see {@link Constants}).
 512   * @param name the method's name.
 513   * @param desc the method's descriptor (see {@link Type Type}).
 514   * @param exceptions the internal names of the method's exceptions. May be
 515   *      <tt>null</tt>.
 516   */
 517
 518  protected void init (
 519    final int access,
 520    final String name,
 521    final String desc,
 522    final String[] exceptions)
 523  {
 524    this.access = access;
 525    this.name = cw.newUTF8(name);
 526    this.desc = cw.newUTF8(desc);
 527    if (exceptions != null && exceptions.length > 0) {
 528      exceptionCount = exceptions.length;
 529      this.exceptions = new int[exceptionCount];
 530      for (int i = 0; i < exceptionCount; ++i) {
 531        this.exceptions[i] = cw.newClass(exceptions[i]).index;
 532      }
 533    }
 534    if (computeMaxs) {
 535      // updates maxLocals
 536      int size = getArgumentsAndReturnSizes(desc) >> 2;
 537      if ((access & Constants.ACC_STATIC) != 0) {
 538        --size;
 539      }
 540      if (size > maxLocals) {
 541        maxLocals = size;
 542      }
 543    }
 544  }
 545
 546  // --------------------------------------------------------------------------
 547  // Implementation of the CodeVisitor interface
 548  // --------------------------------------------------------------------------
 549
 550  public void visitInsn (final int opcode) {
 551    if (computeMaxs) {
 552      // updates current and max stack sizes
 553      int size = stackSize + SIZE[opcode];
 554      if (size > maxStackSize) {
 555        maxStackSize = size;
 556      }
 557      stackSize = size;
 558      // if opcode == ATHROW or xRETURN, ends current block (no successor)
 559      if ((opcode >= Constants.IRETURN && opcode <= Constants.RETURN) ||
 560          opcode == Constants.ATHROW)
 561      {
 562        if (currentBlock != null) {
 563          currentBlock.maxStackSize = maxStackSize;
 564          currentBlock = null;
 565        }
 566      }
 567    }
 568    // adds the instruction to the bytecode of the method
 569    code.put1(opcode);
 570  }
 571
 572  public void visitIntInsn (final int opcode, final int operand) {
 573    if (computeMaxs && opcode != Constants.NEWARRAY) {
 574      // updates current and max stack sizes only if opcode == NEWARRAY
 575      // (stack size variation = 0 for BIPUSH or SIPUSH)
 576      int size = stackSize + 1;
 577      if (size > maxStackSize) {
 578        maxStackSize = size;
 579      }
 580      stackSize = size;
 581    }
 582    // adds the instruction to the bytecode of the method
 583    if (opcode == Constants.SIPUSH) {
 584      code.put12(opcode, operand);
 585    } else { // BIPUSH or NEWARRAY
 586      code.put11(opcode, operand);
 587    }
 588  }
 589
 590  public void visitVarInsn (final int opcode, final int var) {
 591    if (computeMaxs) {
 592      // updates current and max stack sizes
 593      if (opcode == Constants.RET) {
 594        // no stack change, but end of current block (no successor)
 595        if (currentBlock != null) {
 596          currentBlock.maxStackSize = maxStackSize;
 597          currentBlock = null;
 598        }
 599      } else { // xLOAD or xSTORE
 600        int size = stackSize + SIZE[opcode];
 601        if (size > maxStackSize) {
 602          maxStackSize = size;
 603        }
 604        stackSize = size;
 605      }
 606      // updates max locals
 607      int n;
 608      if (opcode == Constants.LLOAD || opcode == Constants.DLOAD ||
 609          opcode == Constants.LSTORE || opcode == Constants.DSTORE)
 610      {
 611        n = var + 2;
 612      } else {
 613        n = var + 1;
 614      }
 615      if (n > maxLocals) {
 616        maxLocals = n;
 617      }
 618    }
 619    // adds the instruction to the bytecode of the method
 620    if (var < 4 && opcode != Constants.RET) {
 621      int opt;
 622      if (opcode < Constants.ISTORE) {
 623        opt = 26 /*ILOAD_0*/ + ((opcode - Constants.ILOAD) << 2) + var;
 624      } else {
 625        opt = 59 /*ISTORE_0*/ + ((opcode - Constants.ISTORE) << 2) + var;
 626      }
 627      code.put1(opt);
 628    } else if (var >= 256) {
 629      code.put1(196 /*WIDE*/).put12(opcode, var);
 630    } else {
 631      code.put11(opcode, var);
 632    }
 633  }
 634
 635  public void visitTypeInsn (final int opcode, final String desc) {
 636    if (computeMaxs && opcode == Constants.NEW) {
 637      // updates current and max stack sizes only if opcode == NEW
 638      // (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF)
 639      int size = stackSize + 1;
 640      if (size > maxStackSize) {
 641        maxStackSize = size;
 642      }
 643      stackSize = size;
 644    }
 645    // adds the instruction to the bytecode of the method
 646    code.put12(opcode, cw.newClass(desc).index);
 647  }
 648
 649  public void visitFieldInsn (
 650    final int opcode,
 651    final String owner,
 652    final String name,
 653    final String desc)
 654  {
 655    if (computeMaxs) {
 656      int size;
 657      // computes the stack size variation
 658      char c = desc.charAt(0);
 659      switch (opcode) {
 660        case Constants.GETSTATIC:
 661          size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
 662          break;
 663        case Constants.PUTSTATIC:
 664          size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
 665          break;
 666        case Constants.GETFIELD:
 667          size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
 668          break;
 669        //case Constants.PUTFIELD:
 670        default:
 671          size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
 672          break;
 673      }
 674      // updates current and max stack sizes
 675      if (size > maxStackSize) {
 676        maxStackSize = size;
 677      }
 678      stackSize = size;
 679    }
 680    // adds the instruction to the bytecode of the method
 681    code.put12(opcode, cw.newField(owner, name, desc).index);
 682  }
 683
 684  public void visitMethodInsn (
 685    final int opcode,
 686    final String owner,
 687    final String name,
 688    final String desc)
 689  {
 690    Item i;
 691    if (opcode == Constants.INVOKEINTERFACE) {
 692      i = cw.newItfMethod(owner, name, desc);
 693    } else {
 694      i = cw.newMethod(owner, name, desc);
 695    }
 696    int argSize = i.intVal;
 697    if (computeMaxs) {
 698      // computes the stack size variation. In order not to recompute several
 699      // times this variation for the same Item, we use the intVal field of
 700      // this item to store this variation, once it has been computed. More
 701      // precisely this intVal field stores the sizes of the arguments and of
 702      // the return value corresponding to desc.
 703      if (argSize == 0) {
 704        // the above sizes have not been computed yet, so we compute them...
 705        argSize = getArgumentsAndReturnSizes(desc);
 706        // ... and we save them in order not to recompute them in the future
 707        i.intVal = argSize;
 708      }
 709      int size;
 710      if (opcode == Constants.INVOKESTATIC) {
 711        size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
 712      } else {
 713        size = stackSize - (argSize >> 2) + (argSize & 0x03);
 714      }
 715      // updates current and max stack sizes
 716      if (size > maxStackSize) {
 717        maxStackSize = size;
 718      }
 719      stackSize = size;
 720    }
 721    // adds the instruction to the bytecode of the method
 722    if (opcode == Constants.INVOKEINTERFACE) {
 723      if (!computeMaxs) {
 724        if (argSize == 0) {
 725          argSize = getArgumentsAndReturnSizes(desc);
 726          i.intVal = argSize;
 727        }
 728      }
 729      code.put12(Constants.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
 730    } else {
 731      code.put12(opcode, i.index);
 732    }
 733  }
 734
 735  public void visitJumpInsn (final int opcode, final Label label) {
 736    if (CHECK) {
 737      if (label.owner == null) {
 738        label.owner = this;
 739      } else if (label.owner != this) {
 740        throw new IllegalArgumentException();
 741      }
 742    }
 743    if (computeMaxs) {
 744      if (opcode == Constants.GOTO) {
 745        // no stack change, but end of current block (with one new successor)
 746        if (currentBlock != null) {
 747          currentBlock.maxStackSize = maxStackSize;
 748          addSuccessor(stackSize, label);
 749          currentBlock = null;
 750        }
 751      } else if (opcode == Constants.JSR) {
 752        if (currentBlock != null) {
 753          addSuccessor(stackSize + 1, label);
 754        }
 755      } else {
 756        // updates current stack size (max stack size unchanged because stack
 757        // size variation always negative in this case)
 758        stackSize += SIZE[opcode];
 759        if (currentBlock != null) {
 760          addSuccessor(stackSize, label);
 761        }
 762      }
 763    }
 764    // adds the instruction to the bytecode of the method
 765    if (label.resolved && label.position - code.length < Short.MIN_VALUE) {
 766      // case of a backward jump with an offset < -32768. In this case we
 767      // automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx <l>
 768      // with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the "opposite" opcode
 769      // of IFxxx (i.e., IFNE for IFEQ) and where <l'> designates the
 770      // instruction just after the GOTO_W.
 771      if (opcode == Constants.GOTO) {
 772        code.put1(200); // GOTO_W
 773      } else if (opcode == Constants.JSR) {
 774        code.put1(201); // JSR_W
 775      } else {
 776        code.put1(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1);
 777        code.put2(8);   // jump offset
 778        code.put1(200); // GOTO_W
 779      }
 780      label.put(this, code, code.length - 1, true);
 781    } else {
 782      // case of a backward jump with an offset >= -32768, or of a forward jump
 783      // with, of course, an unknown offset. In these cases we store the offset
 784      // in 2 bytes (which will be increased in resizeInstructions, if needed).
 785      code.put1(opcode);
 786      label.put(this, code, code.length - 1, false);
 787    }
 788  }
 789
 790  public void visitLabel (final Label label) {
 791    if (CHECK) {
 792      if (label.owner == null) {
 793        label.owner = this;
 794      } else if (label.owner != this) {
 795        throw new IllegalArgumentException();
 796      }
 797    }
 798    if (computeMaxs) {
 799      if (currentBlock != null) {
 800        // ends current block (with one new successor)
 801        currentBlock.maxStackSize = maxStackSize;
 802        addSuccessor(stackSize, label);
 803      }
 804      // begins a new current block,
 805      // resets the relative current and max stack sizes
 806      currentBlock = label;
 807      stackSize = 0;
 808      maxStackSize = 0;
 809    }
 810    // resolves previous forward references to label, if any
 811    resize |= label.resolve(this, code.length, code.data);
 812  }
 813
 814  public void visitLdcInsn (final Object cst) {
 815    Item i = cw.newCst(cst);
 816    if (computeMaxs) {
 817      int size;
 818      // computes the stack size variation
 819      if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
 820        size = stackSize + 2;
 821      } else {
 822        size = stackSize + 1;
 823      }
 824      // updates current and max stack sizes
 825      if (size > maxStackSize) {
 826        maxStackSize = size;
 827      }
 828      stackSize = size;
 829    }
 830    // adds the instruction to the bytecode of the method
 831    int index = i.index;
 832    if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
 833      code.put12(20 /*LDC2_W*/, index);
 834    } else if (index >= 256) {
 835      code.put12(19 /*LDC_W*/, index);
 836    } else {
 837      code.put11(Constants.LDC, index);
 838    }
 839  }
 840
 841  public void visitIincInsn (final int var, final int increment) {
 842    if (computeMaxs) {
 843      // updates max locals only (no stack change)
 844      int n = var + 1;
 845      if (n > maxLocals) {
 846        maxLocals = n;
 847      }
 848    }
 849    // adds the instruction to the bytecode of the method
 850    if ((var > 255) || (increment > 127) || (increment < -128)) {
 851      code.put1(196 /*WIDE*/).put12(Constants.IINC, var).put2(increment);
 852    } else {
 853      code.put1(Constants.IINC).put11(var, increment);
 854    }
 855  }
 856
 857  public void visitTableSwitchInsn (
 858    final int min,
 859    final int max,
 860    final Label dflt,
 861    final Label labels[])
 862  {
 863    if (computeMaxs) {
 864      // updates current stack size (max stack size unchanged)
 865      --stackSize;
 866      // ends current block (with many new successors)
 867      if (currentBlock != null) {
 868        currentBlock.maxStackSize = maxStackSize;
 869        addSuccessor(stackSize, dflt);
 870        for (int i = 0; i < labels.length; ++i) {
 871          addSuccessor(stackSize, labels[i]);
 872        }
 873        currentBlock = null;
 874      }
 875    }
 876    // adds the instruction to the bytecode of the method
 877    int source = code.length;
 878    code.put1(Constants.TABLESWITCH);
 879    while (code.length % 4 != 0) {
 880      code.put1(0);
 881    }
 882    dflt.put(this, code, source, true);
 883    code.put4(min).put4(max);
 884    for (int i = 0; i < labels.length; ++i) {
 885      labels[i].put(this, code, source, true);
 886    }
 887  }
 888
 889  public void visitLookupSwitchInsn (
 890    final Label dflt,
 891    final int keys[],
 892    final Label labels[])
 893  {
 894    if (computeMaxs) {
 895      // updates current stack size (max stack size unchanged)
 896      --stackSize;
 897      // ends current block (with many new successors)
 898      if (currentBlock != null) {
 899        currentBlock.maxStackSize = maxStackSize;
 900        addSuccessor(stackSize, dflt);
 901        for (int i = 0; i < labels.length; ++i) {
 902          addSuccessor(stackSize, labels[i]);
 903        }
 904        currentBlock = null;
 905      }
 906    }
 907    // adds the instruction to the bytecode of the method
 908    int source = code.length;
 909    code.put1(Constants.LOOKUPSWITCH);
 910    while (code.length % 4 != 0) {
 911      code.put1(0);
 912    }
 913    dflt.put(this, code, source, true);
 914    code.put4(labels.length);
 915    for (int i = 0; i < labels.length; ++i) {
 916      code.put4(keys[i]);
 917      labels[i].put(this, code, source, true);
 918    }
 919  }
 920
 921  public void visitMultiANewArrayInsn (final String desc, final int dims) {
 922    if (computeMaxs) {
 923      // updates current stack size (max stack size unchanged because stack
 924      // size variation always negative or null)
 925      stackSize += 1 - dims;
 926    }
 927    // adds the instruction to the bytecode of the method
 928    Item classItem = cw.newClass(desc);
 929    code.put12(Constants.MULTIANEWARRAY, classItem.index).put1(dims);
 930  }
 931
 932  public void visitTryCatchBlock (
 933    final Label start,
 934    final Label end,
 935    final Label handler,
 936    final String type)
 937  {
 938    if (CHECK) {
 939      if (start.owner != this || end.owner != this || handler.owner != this) {
 940        throw new IllegalArgumentException();
 941      }
 942      if (!start.resolved || !end.resolved || !handler.resolved) {
 943        throw new IllegalArgumentException();
 944      }
 945    }
 946    if (computeMaxs) {
 947      // pushes handler block onto the stack of blocks to be visited
 948      if (!handler.pushed) {
 949        handler.beginStackSize = 1;
 950        handler.pushed = true;
 951        handler.next = blockStack;
 952        blockStack = handler;
 953      }
 954    }
 955    ++catchCount;
 956    if (catchTable == null) {
 957      catchTable = new ByteVector();
 958    }
 959    catchTable.put2(start.position);
 960    catchTable.put2(end.position);
 961    catchTable.put2(handler.position);
 962    catchTable.put2(type != null ? cw.newClass(type).index : 0);
 963  }
 964
 965  public void visitMaxs (final int maxStack, final int maxLocals) {
 966    if (computeMaxs) {
 967      // true (non relative) max stack size
 968      int max = 0;
 969      // control flow analysis algorithm: while the block stack is not empty,
 970      // pop a block from this stack, update the max stack size, compute
 971      // the true (non relative) begin stack size of the successors of this
 972      // block, and push these successors onto the stack (unless they have
 973      // already been pushed onto the stack). Note: by hypothesis, the {@link
 974      // Label#beginStackSize} of the blocks in the block stack are the true
 975      // (non relative) beginning stack sizes of these blocks.
 976      Label stack = blockStack;
 977      while (stack != null) {
 978        // pops a block from the stack
 979        Label l = stack;
 980        stack = stack.next;
 981        // computes the true (non relative) max stack size of this block
 982        int start = l.beginStackSize;
 983        int blockMax = start + l.maxStackSize;
 984        // updates the global max stack size
 985        if (blockMax > max) {
 986          max = blockMax;
 987        }
 988        // analyses the successors of the block
 989        Edge b = l.successors;
 990        while (b != null) {
 991          l = b.successor;
 992          // if this successor has not already been pushed onto the stack...
 993          if (!l.pushed) {
 994            // computes the true beginning stack size of this successor block
 995            l.beginStackSize = start + b.stackSize;
 996            // pushes this successor onto the stack
 997            l.pushed = true;
 998            l.next = stack;
 999            stack = l;
1000          }
1001          b = b.next;
1002        }
1003      }
1004      this.maxStack = max;
1005      // releases all the Edge objects used by this CodeWriter
1006      synchronized (SIZE) {
1007        // appends the [head ... tail] list at the beginning of the pool list
1008        if (tail != null) {
1009          tail.poolNext = pool;
1010          pool = head;
1011        }
1012      }
1013    } else {
1014      this.maxStack = maxStack;
1015      this.maxLocals = maxLocals;
1016    }
1017  }
1018
1019  public void visitLocalVariable (
1020    final String name,
1021    final String desc,
1022    final Label start,
1023    final Label end,
1024    final int index)
1025  {
1026    if (CHECK) {
1027      if (start.owner != this || !start.resolved) {
1028        throw new IllegalArgumentException();
1029      }
1030      if (end.owner != this || !end.resolved) {
1031        throw new IllegalArgumentException();
1032      }
1033    }
1034    if (localVar == null) {
1035      cw.newUTF8("LocalVariableTable");
1036      localVar = new ByteVector();
1037    }
1038    ++localVarCount;
1039    localVar.put2(start.position);
1040    localVar.put2(end.position - start.position);
1041    localVar.put2(cw.newUTF8(name).index);
1042    localVar.put2(cw.newUTF8(desc).index);
1043    localVar.put2(index);
1044  }
1045
1046  public void visitLineNumber (final int line, final Label start) {
1047    if (CHECK) {
1048      if (start.owner != this || !start.resolved) {
1049        throw new IllegalArgumentException();
1050      }
1051    }
1052    if (lineNumber == null) {
1053      cw.newUTF8("LineNumberTable");
1054      lineNumber = new ByteVector();
1055    }
1056    ++lineNumberCount;
1057    lineNumber.put2(start.position);
1058    lineNumber.put2(line);
1059  }
1060
1061  // --------------------------------------------------------------------------
1062  // Utility methods: control flow analysis algorithm
1063  // --------------------------------------------------------------------------
1064
1065  /**
1066   * Computes the size of the arguments and of the return value of a method.
1067   *
1068   * @param desc the descriptor of a method.
1069   * @return the size of the arguments of the method (plus one for the implicit
1070   *      this argument), argSize, and the size of its return value, retSize,
1071   *      packed into a single int i = <tt>(argSize << 2) | retSize</tt>
1072   *      (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
1073   *      <tt>i & 0x03</tt>).
1074   */
1075
1076  private static int getArgumentsAndReturnSizes (final String desc) {
1077    int n = 1;
1078    int c = 1;
1079    while (true) {
1080      char car = desc.charAt(c++);
1081      if (car == ')') {
1082        car = desc.charAt(c);
1083        return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
1084      } else if (car == 'L') {
1085        while (desc.charAt(c++) != ';') {
1086        }
1087        n += 1;
1088      } else if (car == '[') {
1089        while ((car = desc.charAt(c)) == '[') {
1090          ++c;
1091        }
1092        if (car == 'D' || car == 'J') {
1093          n -= 1;
1094        }
1095      } else if (car == 'D' || car == 'J') {
1096        n += 2;
1097      } else {
1098        n += 1;
1099      }
1100    }
1101  }
1102
1103  /**
1104   * Adds a successor to the {@link #currentBlock currentBlock} block.
1105   *
1106   * @param stackSize the current (relative) stack size in the current block.
1107   * @param successor the successor block to be added to the current block.
1108   */
1109
1110  private void addSuccessor (final int stackSize, final Label successor) {
1111    Edge b;
1112    // creates a new Edge object or reuses one from the shared pool
1113    synchronized (SIZE) {
1114      if (pool == null) {
1115        b = new Edge();
1116      } else {
1117        b = pool;
1118        // removes b from the pool
1119        pool = pool.poolNext;
1120      }
1121    }
1122    // adds the previous Edge to the list of Edges used by this CodeWriter
1123    if (tail == null) {
1124      tail = b;
1125    }
1126    b.poolNext = head;
1127    head = b;
1128    // initializes the previous Edge object...
1129    b.stackSize = stackSize;
1130    b.successor = successor;
1131    // ...and adds it to the successor list of the currentBlock block
1132    b.next = currentBlock.successors;
1133    currentBlock.successors = b;
1134  }
1135
1136  // --------------------------------------------------------------------------
1137  // Utility methods: dump bytecode array
1138  // --------------------------------------------------------------------------
1139
1140  /**
1141   * Returns the size of the bytecode of this method.
1142   *
1143   * @return the size of the bytecode of this method.
1144   */
1145
1146  final int getSize () {
1147    if (resize) {
1148      // replaces the temporary jump opcodes introduced by Label.resolve.
1149      resizeInstructions(new int[0], new int[0], 0);
1150    }
1151    int size = 8;
1152    if (code.length > 0) {
1153      cw.newUTF8("Code");
1154      size += 18 + code.length + 8 * catchCount;
1155      if (localVar != null) {
1156        size += 8 + localVar.length;
1157      }
1158      if (lineNumber != null) {
1159        size += 8 + lineNumber.length;
1160      }
1161    }
1162    if (exceptionCount > 0) {
1163      cw.newUTF8("Exceptions");
1164      size += 8 + 2 * exceptionCount;
1165    }
1166    if ((access & Constants.ACC_SYNTHETIC) != 0) {
1167      cw.newUTF8("Synthetic");
1168      size += 6;
1169    }
1170    if ((access & Constants.ACC_DEPRECATED) != 0) {
1171      cw.newUTF8("Deprecated");
1172      size += 6;
1173    }
1174    return size;
1175  }
1176
1177  /**
1178   * Puts the bytecode of this method in the given byte vector.
1179   *
1180   * @param out the byte vector into which the bytecode of this method must be
1181   *      copied.
1182   */
1183
1184  final void put (final ByteVector out) {
1185    out.put2(access).put2(name.index).put2(desc.index);
1186    int attributeCount = 0;
1187    if (code.length > 0) {
1188      ++attributeCount;
1189    }
1190    if (exceptionCount > 0) {
1191      ++attributeCount;
1192    }
1193    if ((access & Constants.ACC_SYNTHETIC) != 0) {
1194      ++attributeCount;
1195    }
1196    if ((access & Constants.ACC_DEPRECATED) != 0) {
1197      ++attributeCount;
1198    }
1199    out.put2(attributeCount);
1200    if (code.length > 0) {
1201      int size = 12 + code.length + 8 * catchCount;
1202      if (localVar != null) {
1203        size += 8 + localVar.length;
1204      }
1205      if (lineNumber != null) {
1206        size += 8 + lineNumber.length;
1207      }
1208      out.put2(cw.newUTF8("Code").index).put4(size);
1209      out.put2(maxStack).put2(maxLocals);
1210      out.put4(code.length).putByteArray(code.data, 0, code.length);
1211      out.put2(catchCount);
1212      if (catchCount > 0) {
1213        out.putByteArray(catchTable.data, 0, catchTable.length);
1214      }
1215      attributeCount = 0;
1216      if (localVar != null) {
1217        ++attributeCount;
1218      }
1219      if (lineNumber != null) {
1220        ++attributeCount;
1221      }
1222      out.put2(attributeCount);
1223      if (localVar != null) {
1224        out.put2(cw.newUTF8("LocalVariableTable").index);
1225        out.put4(localVar.length + 2).put2(localVarCount);
1226        out.putByteArray(localVar.data, 0, localVar.length);
1227      }
1228      if (lineNumber != null) {
1229        out.put2(cw.newUTF8("LineNumberTable").index);
1230        out.put4(lineNumber.length + 2).put2(lineNumberCount);
1231        out.putByteArray(lineNumber.data, 0, lineNumber.length);
1232      }
1233    }
1234    if (exceptionCount > 0) {
1235      out.put2(cw.newUTF8("Exceptions").index).put4(2 * exceptionCount + 2);
1236      out.put2(exceptionCount);
1237      for (int i = 0; i < exceptionCount; ++i) {
1238        out.put2(exceptions[i]);
1239      }
1240    }
1241    if ((access & Constants.ACC_SYNTHETIC) != 0) {
1242      out.put2(cw.newUTF8("Synthetic").index).put4(0);
1243    }
1244    if ((access & Constants.ACC_DEPRECATED) != 0) {
1245      out.put2(cw.newUTF8("Deprecated").index).put4(0);
1246    }
1247  }
1248
1249  // --------------------------------------------------------------------------
1250  // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
1251  // --------------------------------------------------------------------------
1252
1253  /**
1254   * Resizes the designated instructions, while keeping jump offsets and
1255   * instruction addresses consistent. This may require to resize other existing
1256   * instructions, or even to introduce new instructions: for example,
1257   * increasing the size of an instruction by 2 at the middle of a method can
1258   * increases the offset of an IFEQ instruction from 32766 to 32768, in which
1259   * case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W 32765. This, in turn,
1260   * may require to increase the size of another jump instruction, and so on...
1261   * All these operations are handled automatically by this method.
1262   * <p>
1263   * <i>This method must be called after all the method that is being built has
1264   * been visited</i>. In particular, the {@link Label Label} objects used to
1265   * construct the method are no longer valid after this method has been called.
1266   *
1267   * @param indexes current positions of the instructions to be resized. Each
1268   *      instruction must be designated by the index of its <i>last</i> byte,
1269   *      plus one (or, in other words, by the index of the <i>first</i> byte of
1270   *      the <i>next</i> instruction).
1271   * @param sizes the number of bytes to be <i>added</i> to the above
1272   *      instructions. More precisely, for each i &lt; <tt>len</tt>,
1273   *      <tt>sizes</tt>[i] bytes will be added at the end of the instruction
1274   *      designated by <tt>indexes</tt>[i] or, if <tt>sizes</tt>[i] is
1275   *      negative, the <i>last</i> |<tt>sizes[i]</tt>| bytes of the instruction
1276   *      will be removed (the instruction size <i>must not</i> become negative
1277   *      or null). The gaps introduced by this method must be filled in
1278   *      "manually" in the array returned by the {@link #getCode getCode}
1279   *      method.
1280   * @param len the number of instruction to be resized. Must be smaller than or
1281   *      equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
1282   * @return the <tt>indexes</tt> array, which now contains the new positions of
1283   *      the resized instructions (designated as above).
1284   */
1285
1286  protected int[] resizeInstructions (
1287    final int[] indexes,
1288    final int[] sizes,
1289    final int len)
1290  {
1291    byte[] b = code.data; // bytecode of the method
1292    int u, v, label;      // indexes in b
1293    int i, j;             // loop indexes
1294
1295    // 1st step:
1296    // As explained above, resizing an instruction may require to resize another
1297    // one, which may require to resize yet another one, and so on. The first
1298    // step of the algorithm consists in finding all the instructions that
1299    // need to be resized, without modifying the code. This is done by the
1300    // following "fix point" algorithm:
1301    // - parse the code to find the jump instructions whose offset will need
1302    //   more than 2 bytes to be stored (the future offset is computed from the
1303    //   current offset and from the number of bytes that will be inserted or
1304    //   removed between the source and target instructions). For each such
1305    //   instruction, adds an entry in (a copy of) the indexes and sizes arrays
1306    //   (if this has not already been done in a previous iteration!)
1307    // - if at least one entry has been added during the previous step, go back
1308    //   to the beginning, otherwise stop.
1309    // In fact the real algorithm is complicated by the fact that the size of
1310    // TABLESWITCH and LOOKUPSWITCH instructions depends on their position in
1311    // the bytecode (because of padding). In order to ensure the convergence of
1312    // the algorithm, the number of bytes to be added or removed from these
1313    // instructions is over estimated during the previous loop, and computed
1314    // exactly only after the loop is finished (this requires another pass to
1315    // parse the bytecode of the method).
1316
1317    int[] allIndexes = new int[len]; // copy of indexes
1318    int[] allSizes = new int[len];   // copy of sizes
1319    boolean[] resize;                // instructions to be resized
1320    int newOffset;                   // future offset of a jump instruction
1321
1322    System.arraycopy(indexes, 0, allIndexes, 0, len);
1323    System.arraycopy(sizes, 0, allSizes, 0, len);
1324    resize = new boolean[code.length];
1325
1326    int state = 3; // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
1327    do {
1328      if (state == 3) {
1329        state = 2;
1330      }
1331      u = 0;
1332      while (u < b.length) {
1333        int opcode = b[u] & 0xFF;  // opcode of current instruction
1334        int insert = 0;            // bytes to be added after this instruction
1335
1336        switch (ClassWriter.TYPE[opcode]) {
1337          case ClassWriter.NOARG_INSN:
1338          case ClassWriter.IMPLVAR_INSN:
1339            u += 1;
1340            break;
1341          case ClassWriter.LABEL_INSN:
1342            if (opcode > 201) {
1343              // converts temporary opcodes 202 to 217 (inclusive), 218 and 219
1344              // to IFEQ ... JSR (inclusive), IFNULL and IFNONNULL
1345              opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1346              label = u + readUnsignedShort(b, u + 1);
1347            } else {
1348              label = u + readShort(b, u + 1);
1349            }
1350            newOffset = getNewOffset(allIndexes, allSizes, u, label);
1351            if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) {
1352              if (!resize[u]) {
1353                if (opcode == Constants.GOTO || opcode == Constants.JSR) {
1354                  // two additional bytes will be required to replace this
1355                  // GOTO or JSR instruction with a GOTO_W or a JSR_W
1356                  insert = 2;
1357                } else {
1358                  // five additional bytes will be required to replace this
1359                  // IFxxx <l> instruction with IFNOTxxx <l'> GOTO_W <l>, where
1360                  // IFNOTxxx is the "opposite" opcode of IFxxx (i.e., IFNE for
1361                  // IFEQ) and where <l'> designates the instruction just after
1362                  // the GOTO_W.
1363                  insert = 5;
1364                }
1365                resize[u] = true;
1366              }
1367            }
1368            u += 3;
1369            break;
1370          case ClassWriter.LABELW_INSN:
1371            u += 5;
1372            break;
1373          case ClassWriter.TABL_INSN:
1374            if (state == 1) {
1375              // true number of bytes to be added (or removed) from this
1376              // instruction = (future number of padding bytes - current number
1377              // of padding byte) - previously over estimated variation =
1378              // = ((3 - newOffset%4) - (3 - u%4)) - u%4
1379              // = (-newOffset%4 + u%4) - u%4
1380              // = -(newOffset & 3)
1381              newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1382              insert = -(newOffset & 3);
1383            } else if (!resize[u]) {
1384              // over estimation of the number of bytes to be added to this
1385              // instruction = 3 - current number of padding bytes = 3 - (3 -
1386              // u%4) = u%4 = u & 3
1387              insert = u & 3;
1388              resize[u] = true;
1389            }
1390            // skips instruction
1391            u = u + 4 - (u & 3);
1392            u += 4*(readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
1393            break;
1394          case ClassWriter.LOOK_INSN:
1395            if (state == 1) {
1396              // like TABL_INSN
1397              newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1398              insert = -(newOffset & 3);
1399            } else if (!resize[u]) {
1400              // like TABL_INSN
1401              insert = u & 3;
1402              resize[u] = true;
1403            }
1404            // skips instruction
1405            u = u + 4 - (u & 3);
1406            u += 8*readInt(b, u + 4) + 8;
1407            break;
1408          case ClassWriter.WIDE_INSN:
1409            opcode = b[u + 1] & 0xFF;
1410            if (opcode == Constants.IINC) {
1411              u += 6;
1412            } else {
1413              u += 4;
1414            }
1415            break;
1416          case ClassWriter.VAR_INSN:
1417          case ClassWriter.SBYTE_INSN:
1418          case ClassWriter.LDC_INSN:
1419            u += 2;
1420            break;
1421          case ClassWriter.SHORT_INSN:
1422          case ClassWriter.LDCW_INSN:
1423          case ClassWriter.FIELDORMETH_INSN:
1424          case ClassWriter.TYPE_INSN:
1425          case ClassWriter.IINC_INSN:
1426            u += 3;
1427            break;
1428          case ClassWriter.ITFMETH_INSN:
1429            u += 5;
1430            break;
1431          // case ClassWriter.MANA_INSN:
1432          default:
1433            u += 4;
1434            break;
1435        }
1436        if (insert != 0) {
1437          // adds a new (u, insert) entry in the allIndexes and allSizes arrays
1438          int[] newIndexes = new int[allIndexes.length + 1];
1439          int[] newSizes = new int[allSizes.length + 1];
1440          System.arraycopy(allIndexes, 0, newIndexes, 0, allIndexes.length);
1441          System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
1442          newIndexes[allIndexes.length] = u;
1443          newSizes[allSizes.length] = insert;
1444          allIndexes = newIndexes;
1445          allSizes = newSizes;
1446          if (insert > 0) {
1447            state = 3;
1448          }
1449        }
1450      }
1451      if (state < 3) {
1452        --state;
1453      }
1454    } while (state != 0);
1455
1456    // 2nd step:
1457    // copies the bytecode of the method into a new bytevector, updates the
1458    // offsets, and inserts (or removes) bytes as requested.
1459
1460    ByteVector newCode = new ByteVector(code.length);
1461
1462    u = 0;
1463    while (u < code.length) {
1464      for (i = allIndexes.length - 1; i >= 0; --i) {
1465        if (allIndexes[i] == u) {
1466          if (i < len) {
1467            if (sizes[i] > 0) {
1468              newCode.putByteArray(null, 0, sizes[i]);
1469            } else {
1470              newCode.length += sizes[i];
1471            }
1472            indexes[i] = newCode.length;
1473          }
1474        }
1475      }
1476      int opcode = b[u] & 0xFF;
1477      switch (ClassWriter.TYPE[opcode]) {
1478        case ClassWriter.NOARG_INSN:
1479        case ClassWriter.IMPLVAR_INSN:
1480          newCode.put1(opcode);
1481          u += 1;
1482          break;
1483        case ClassWriter.LABEL_INSN:
1484          if (opcode > 201) {
1485            // changes temporary opcodes 202 to 217 (inclusive), 218 and 219
1486            // to IFEQ ..

Large files files are truncated, but you can click here to view the full file