Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2007 INRIA, France Telecom All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  package org.objectweb.asm;

A MethodVisitor that generates methods in bytecode form. Each visit method of this class appends the bytecode corresponding to the visited instruction to a byte vector, in the order these methods are called.

Author(s):
Eric Bruneton
Eugene Kuleshov
  
  class MethodWriter implements MethodVisitor {

    
Pseudo access flag used to denote constructors.
  
      static final int ACC_CONSTRUCTOR = 262144;

    
Frame has exactly the same locals as the previous stack map frame and number of stack items is zero.
  
      static final int SAME_FRAME = 0; // to 63 (0-3f)
  
    
Frame has exactly the same locals as the previous stack map frame and number of stack items is 1
  
      static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
  
    
Reserved for future use
  
      static final int RESERVED = 128;

    
Frame has exactly the same locals as the previous stack map frame and number of stack items is 1. Offset is bigger then 63;
  
      static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
  
    
Frame where current locals are the same as the locals in the previous frame, except that the k last locals are absent. The value of k is given by the formula 251-frame_type.
  
      static final int CHOP_FRAME = 248; // to 250 (f8-fA)
  
    
Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. Offset is bigger then 63;
  
      static final int SAME_FRAME_EXTENDED = 251; // fb
  
    
Frame where current locals are the same as the locals in the previous frame, except that k additional locals are defined. The value of k is given by the formula frame_type-251.
  
      static final int APPEND_FRAME = 252; // to 254 // fc-fe
  
    
Full frame
  
      static final int FULL_FRAME = 255; // ff
  
    
Indicates that the stack map frames must be recomputed from scratch. In this case the maximum stack size and number of local variables is also recomputed from scratch.

See also:
compute
 
     private static final int FRAMES = 0;

    
Indicates that the maximum stack size and number of local variables must be automatically computed.

See also:
compute
 
     private static final int MAXS = 1;

    
Indicates that nothing must be automatically computed.

See also:
compute
 
     private static final int NOTHING = 2;

    
Next method writer (see firstMethod).
 
     MethodWriter next;

    
The class writer to which this method must be added.
 
     final ClassWriter cw;

    
Access flags of this method.
 
     private int access;

    
The index of the constant pool item that contains the name of this method.
 
     private final int name;

    
The index of the constant pool item that contains the descriptor of this method.
 
     private final int desc;

    
The descriptor of this method.
 
     private final String descriptor;

    
The signature of this method.
 
     String signature;

    
If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer in cw.cr. More precisely, this field gives the index of the first byte to copied from cw.cr.b.
 
     int classReaderOffset;

    
If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer in cw.cr. More precisely, this field gives the number of bytes to copied from cw.cr.b.
 
     int classReaderLength;

    
Number of exceptions that can be thrown by this method.
 
     int exceptionCount;

    
The exceptions that can be thrown by this method. More precisely, this array contains the indexes of the constant pool items that contain the internal names of these exception classes.
 
     int[] exceptions;

    
The annotation default attribute of this method. May be null.
 
     private ByteVector annd;

    
The runtime visible annotations of this method. May be null.
 
     private AnnotationWriter anns;

    
The runtime invisible annotations of this method. May be null.
 
     private AnnotationWriter ianns;

    
The runtime visible parameter annotations of this method. May be null.
 
     private AnnotationWriter[] panns;

    
The runtime invisible parameter annotations of this method. May be null.
 
     private AnnotationWriter[] ipanns;

    
The number of synthetic parameters of this method.
 
     private int synthetics;

    
The non standard attributes of the method.
 
     private Attribute attrs;

    
The bytecode of this method.
 
     private ByteVector code = new ByteVector();

    
Maximum stack size of this method.
 
     private int maxStack;

    
Maximum number of local variables for this method.
 
     private int maxLocals;

    
Number of stack map frames in the StackMapTable attribute.
 
     private int frameCount;

    
The StackMapTable attribute.
 
     private ByteVector stackMap;

    
The offset of the last frame that was written in the StackMapTable attribute.
 
     private int previousFrameOffset;

    
The last frame that was written in the StackMapTable attribute.

See also:
frame
 
     private int[] previousFrame;

    
Index of the next element to be added in frame.
 
     private int frameIndex;

    
The current stack map frame. The first element contains the offset of the instruction to which the frame corresponds, the second element is the number of locals and the third one is the number of stack elements. The local variables start at index 3 and are followed by the operand stack values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = nStack, frame[3] = nLocal. All types are encoded as integers, with the same format as the one used in Label, but limited to BASE types.
 
     private int[] frame;

    
Number of elements in the exception handler list.
 
     private int handlerCount;

    
The first element in the exception handler list.
 
     private Handler firstHandler;

    
The last element in the exception handler list.
 
     private Handler lastHandler;

    
Number of entries in the LocalVariableTable attribute.
 
     private int localVarCount;

    
The LocalVariableTable attribute.
 
     private ByteVector localVar;

    
Number of entries in the LocalVariableTypeTable attribute.
 
     private int localVarTypeCount;

    
The LocalVariableTypeTable attribute.
 
     private ByteVector localVarType;

    
Number of entries in the LineNumberTable attribute.
 
     private int lineNumberCount;

    
The LineNumberTable attribute.
 
     private ByteVector lineNumber;

    
The non standard attributes of the method's code.
 
     private Attribute cattrs;

    
Indicates if some jump instructions are too small and need to be resized.
 
     private boolean resize;

    
The number of subroutines in this method.
 
     private int subroutines;
 
     // ------------------------------------------------------------------------
 
     /*
      * Fields for the control flow graph analysis algorithm (used to compute the
      * maximum stack size). A control flow graph contains one node per "basic
      * block", and one edge per "jump" from one basic block to another. Each
      * node (i.e., each basic block) is represented by the Label object that
      * corresponds to the first instruction of this basic block. Each node also
      * stores the list of its successors in the graph, as a linked list of Edge
      * objects.
      */

    
Indicates what must be automatically computed.

 
     private final int compute;

    
A list of labels. This list is the list of basic blocks in the method, i.e. a list of Label objects linked to each other by their Label.successor field, in the order they are visited by MethodVisitor.visitLabel(org.objectweb.asm.Label), and starting with the first basic block.
 
     private Label labels;

    
The previous basic block.
 
     private Label previousBlock;

    
The current basic block.
 
     private Label currentBlock;

    
The (relative) stack size after the last visited instruction. This size is relative to the beginning of the current basic block, i.e., the true stack size after the last visited instruction is equal to the beginStackSize of the current basic block plus stackSize.
 
     private int stackSize;

    
The (relative) maximum stack size after the last visited instruction. This size is relative to the beginning of the current basic block, i.e., the true maximum stack size after the last visited instruction is equal to the beginStackSize of the current basic block plus stackSize.
 
     private int maxStackSize;
 
     // ------------------------------------------------------------------------
     // Constructor
     // ------------------------------------------------------------------------
 
    
Constructs a new MethodWriter.

Parameters:
cw the class writer in which the method must be added.
access the method's access flags (see Opcodes).
name the method's name.
desc the method's descriptor (see Type).
signature the method's signature. May be null.
exceptions the internal names of the method's exceptions. May be null.
computeMaxs true if the maximum stack size and number of local variables must be automatically computed.
computeFrames true if the stack map tables must be recomputed from scratch.
 
     MethodWriter(
         final ClassWriter cw,
         final int access,
         final String name,
         final String desc,
         final String signature,
         final String[] exceptions,
         final boolean computeMaxs,
         final boolean computeFrames)
     {
         if (cw.firstMethod == null) {
             cw.firstMethod = this;
         } else {
             cw.lastMethod.next = this;
         }
         cw.lastMethod = this;
         this. = cw;
         this. = access;
         this. = cw.newUTF8(name);
         this. = cw.newUTF8(desc);
         this. = desc;
         if (.) {
             this. = signature;
         }
         if (exceptions != null && exceptions.length > 0) {
              = exceptions.length;
             this. = new int[];
             for (int i = 0; i < ; ++i) {
                 this.[i] = cw.newClass(exceptions[i]);
             }
         }
         this. = computeFrames ?  : (computeMaxs ?  : );
         if (computeMaxs || computeFrames) {
             if (computeFrames && "<init>".equals(name)) {
                 this. |= ;
             }
             // updates maxLocals
             int size = getArgumentsAndReturnSizes() >> 2;
             if ((access & .) != 0) {
                 --size;
             }
              = size;
             // creates and visits the label for the first basic block
              = new Label();
             . |= .;
             visitLabel();
         }
     }
 
     // ------------------------------------------------------------------------
     // Implementation of the MethodVisitor interface
     // ------------------------------------------------------------------------
 
         if (!.) {
             return null;
         }
          = new ByteVector();
         return new AnnotationWriter(falsenull, 0);
     }
 
         final String desc,
         final boolean visible)
     {
         if (!.) {
             return null;
         }
         ByteVector bv = new ByteVector();
         // write type, and reserve space for values count
         bv.putShort(.newUTF8(desc)).putShort(0);
         AnnotationWriter aw = new AnnotationWriter(truebvbv, 2);
         if (visible) {
             aw.next = ;
              = aw;
         } else {
             aw.next = ;
              = aw;
         }
         return aw;
     }
 
         final int parameter,
         final String desc,
         final boolean visible)
     {
         if (!.) {
             return null;
         }
         ByteVector bv = new ByteVector();
         if ("Ljava/lang/Synthetic;".equals(desc)) {
             // workaround for a bug in javac with synthetic parameters
             // see ClassReader.readParameterAnnotations
              = Math.max(parameter + 1);
             return new AnnotationWriter(falsebvnull, 0);
         }
         // write type, and reserve space for values count
         bv.putShort(.newUTF8(desc)).putShort(0);
         AnnotationWriter aw = new AnnotationWriter(truebvbv, 2);
         if (visible) {
             if ( == null) {
                  = new AnnotationWriter[Type.getArgumentTypes().length];
             }
             aw.next = [parameter];
             [parameter] = aw;
         } else {
             if ( == null) {
                  = new AnnotationWriter[Type.getArgumentTypes().length];
             }
             aw.next = [parameter];
             [parameter] = aw;
         }
         return aw;
     }
 
     public void visitAttribute(final Attribute attr) {
         if (attr.isCodeAttribute()) {
             attr.next = ;
              = attr;
         } else {
             attr.next = ;
              = attr;
         }
     }
 
     public void visitCode() {
     }
 
     public void visitFrame(
         final int type,
         final int nLocal,
         final Object[] local,
         final int nStack,
         final Object[] stack)
     {
         if (!. ||  == ) {
             return;
         }
 
         if (type == .) {
             startFrame(.nLocalnStack);
             for (int i = 0; i < nLocal; ++i) {
                 if (local[iinstanceof String) {
                     [++] = .
                             | .addType((Stringlocal[i]);
                 } else if (local[iinstanceof Integer) {
                     [++] = ((Integerlocal[i]).intValue();
                 } else {
                     [++] = .
                             | .addUninitializedType("",
                                     ((Labellocal[i]).);
                 }
             }
             for (int i = 0; i < nStack; ++i) {
                 if (stack[iinstanceof String) {
                     [++] = .
                             | .addType((Stringstack[i]);
                 } else if (stack[iinstanceof Integer) {
                     [++] = ((Integerstack[i]).intValue();
                 } else {
                     [++] = .
                             | .addUninitializedType("",
                                     ((Labelstack[i]).);
                 }
             }
             endFrame();
         } else {
             int delta;
             if ( == null) {
                  = new ByteVector();
                 delta = .;
             } else {
                 delta = . -  - 1;
             }
 
             switch (type) {
                 case .:
                     .putByte()
                             .putShort(delta)
                             .putShort(nLocal);
                     for (int i = 0; i < nLocal; ++i) {
                         writeFrameType(local[i]);
                     }
                     .putShort(nStack);
                     for (int i = 0; i < nStack; ++i) {
                         writeFrameType(stack[i]);
                     }
                     break;
                 case .:
                     .putByte( + nLocal)
                             .putShort(delta);
                     for (int i = 0; i < nLocal; ++i) {
                         writeFrameType(local[i]);
                     }
                     break;
                 case .:
                     .putByte( - nLocal)
                             .putShort(delta);
                     break;
                 case .:
                     if (delta < 64) {
                         .putByte(delta);
                     } else {
                         .putByte().putShort(delta);
                     }
                     break;
                 case .:
                     if (delta < 64) {
                         .putByte( + delta);
                     } else {
                         .putByte()
                                 .putShort(delta);
                     }
                     writeFrameType(stack[0]);
                     break;
             }
 
              = .;
             ++;
         }
     }
 
     public void visitInsn(final int opcode) {
         // adds the instruction to the bytecode of the method
         .putByte(opcode);
         // update currentBlock
         // Label currentBlock = this.currentBlock;
         if ( != null) {
             if ( == ) {
                 ..execute(opcode, 0, nullnull);
             } else {
                 // updates current and max stack sizes
                 int size =  + .[opcode];
                 if (size > ) {
                      = size;
                 }
                  = size;
             }
             // if opcode == ATHROW or xRETURN, ends current block (no successor)
             if ((opcode >= . && opcode <= .)
                     || opcode == .)
             {
                 noSuccessor();
             }
         }
     }
 
     public void visitIntInsn(final int opcodefinal int operand) {
         // Label currentBlock = this.currentBlock;
         if ( != null) {
             if ( == ) {
                 ..execute(opcodeoperandnullnull);
             } else if (opcode != .) {
                 // updates current and max stack sizes only for NEWARRAY
                 // (stack size variation = 0 for BIPUSH or SIPUSH)
                 int size =  + 1;
                 if (size > ) {
                      = size;
                 }
                  = size;
             }
         }
         // adds the instruction to the bytecode of the method
         if (opcode == .) {
             .put12(opcodeoperand);
         } else { // BIPUSH or NEWARRAY
             .put11(opcodeoperand);
         }
     }
 
     public void visitVarInsn(final int opcodefinal int var) {
         // Label currentBlock = this.currentBlock;
         if ( != null) {
             if ( == ) {
                 ..execute(opcodevarnullnull);
             } else {
                 // updates current and max stack sizes
                 if (opcode == .) {
                     // no stack change, but end of current block (no successor)
                     . |= .;
                     // save 'stackSize' here for future use
                     // (see {@link #findSubroutineSuccessors})
                     . = ;
                     noSuccessor();
                 } else { // xLOAD or xSTORE
                     int size =  + .[opcode];
                     if (size > ) {
                          = size;
                     }
                      = size;
                 }
             }
         }
         if ( != ) {
             // updates max locals
             int n;
             if (opcode == . || opcode == .
                     || opcode == . || opcode == .)
             {
                 n = var + 2;
             } else {
                 n = var + 1;
             }
             if (n > ) {
                  = n;
             }
         }
         // adds the instruction to the bytecode of the method
         if (var < 4 && opcode != .) {
             int opt;
             if (opcode < .) {
                 /* ILOAD_0 */
                 opt = 26 + ((opcode - .) << 2) + var;
             } else {
                 /* ISTORE_0 */
                 opt = 59 + ((opcode - .) << 2) + var;
             }
             .putByte(opt);
         } else if (var >= 256) {
             .putByte(196 /* WIDE */).put12(opcodevar);
         } else {
             .put11(opcodevar);
         }
         if (opcode >= . &&  ==  &&  > 0) {
             visitLabel(new Label());
         }
     }
 
     public void visitTypeInsn(final int opcodefinal String type) {
         Item i = .newClassItem(type);
         // Label currentBlock = this.currentBlock;
         if ( != null) {
             if ( == ) {
                 ..execute(opcode.i);
             } else if (opcode == .) {
                 // updates current and max stack sizes only if opcode == NEW
                 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
                 int size =  + 1;
                 if (size > ) {
                      = size;
                 }
                  = size;
             }
         }
         // adds the instruction to the bytecode of the method
         .put12(opcodei.index);
     }
 
     public void visitFieldInsn(
         final int opcode,
         final String owner,
         final String name,
         final String desc)
     {
         Item i = .newFieldItem(ownernamedesc);
         // Label currentBlock = this.currentBlock;
         if ( != null) {
             if ( == ) {
                 ..execute(opcode, 0, i);
             } else {
                 int size;
                 // computes the stack size variation
                 char c = desc.charAt(0);
                 switch (opcode) {
                     case .:
                         size =  + (c == 'D' || c == 'J' ? 2 : 1);
                         break;
                     case .:
                         size =  + (c == 'D' || c == 'J' ? -2 : -1);
                         break;
                     case .:
                         size =  + (c == 'D' || c == 'J' ? 1 : 0);
                         break;
                     // case Constants.PUTFIELD:
                     default:
                         size =  + (c == 'D' || c == 'J' ? -3 : -2);
                         break;
                 }
                 // updates current and max stack sizes
                 if (size > ) {
                      = size;
                 }
                  = size;
             }
         }
         // adds the instruction to the bytecode of the method
         .put12(opcodei.index);
     }
 
     public void visitMethodInsn(
         final int opcode,
         final String owner,
         final String name,
         final String desc)
     {
         boolean itf = opcode == .;
         Item i = .newMethodItem(ownernamedescitf);
         int argSize = i.intVal;
         // Label currentBlock = this.currentBlock;
         if ( != null) {
             if ( == ) {
                 ..execute(opcode, 0, i);
             } else {
                 /*
                  * computes the stack size variation. In order not to recompute
                  * several times this variation for the same Item, we use the
                  * intVal field of this item to store this variation, once it
                  * has been computed. More precisely this intVal field stores
                  * the sizes of the arguments and of the return value
                  * corresponding to desc.
                  */
                 if (argSize == 0) {
                     // the above sizes have not been computed yet,
                     // so we compute them...
                     argSize = getArgumentsAndReturnSizes(desc);
                     // ... and we save them in order
                     // not to recompute them in the future
                     i.intVal = argSize;
                 }
                 int size;
                 if (opcode == .) {
                     size =  - (argSize >> 2) + (argSize & 0x03) + 1;
                 } else {
                     size =  - (argSize >> 2) + (argSize & 0x03);
                 }
                 // updates current and max stack sizes
                 if (size > ) {
                      = size;
                 }
                  = size;
             }
         }
         // adds the instruction to the bytecode of the method
         if (itf) {
             if (argSize == 0) {
                 argSize = getArgumentsAndReturnSizes(desc);
                 i.intVal = argSize;
             }
             .put12(.i.index).put11(argSize >> 2, 0);
         } else {
             .put12(opcodei.index);
         }
     }
 
     public void visitJumpInsn(final int opcodefinal Label label) {
         Label nextInsn = null;
         // Label currentBlock = this.currentBlock;
         if ( != null) {
             if ( == ) {
                 ..execute(opcode, 0, nullnull);
                 // 'label' is the target of a jump instruction
                 label.getFirst(). |= .;
                 // adds 'label' as a successor of this basic block
                 addSuccessor(.label);
                 if (opcode != .) {
                     // creates a Label for the next basic block
                     nextInsn = new Label();
                 }
             } else {
                 if (opcode == .) {
                     if ((label.status & .) == 0) {
                         label.status |= .;
                         ++;
                     }
                     . |= .;
                     addSuccessor( + 1, label);
                     // creates a Label for the next basic block
                     nextInsn = new Label();
                     /*
                      * note that, by construction in this method, a JSR block
                      * has at least two successors in the control flow graph:
                      * the first one leads the next instruction after the JSR,
                      * while the second one leads to the JSR target.
                      */
                 } else {
                     // updates current stack size (max stack size unchanged
                     // because stack size variation always negative in this
                     // case)
                      += .[opcode];
                     addSuccessor(label);
                 }
             }
         }
         // adds the instruction to the bytecode of the method
         if ((label.status & .) != 0
                 && label.position - . < .)
         {
             /*
              * case of a backward jump with an offset < -32768. In this case we
              * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
              * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
              * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
              * designates the instruction just after the GOTO_W.
              */
             if (opcode == .) {
                 .putByte(200); // GOTO_W
             } else if (opcode == .) {
                 .putByte(201); // JSR_W
             } else {
                 // if the IF instruction is transformed into IFNOT GOTO_W the
                 // next instruction becomes the target of the IFNOT instruction
                 if (nextInsn != null) {
                     nextInsn.status |= .;
                 }
                 .putByte(opcode <= 166
                         ? ((opcode + 1) ^ 1) - 1
                         : opcode ^ 1);
                 .putShort(8); // jump offset
                 .putByte(200); // GOTO_W
             }
             label.put(this. - 1, true);
         } else {
             /*
              * case of a backward jump with an offset >= -32768, or of a forward
              * jump with, of course, an unknown offset. In these cases we store
              * the offset in 2 bytes (which will be increased in
              * resizeInstructions, if needed).
              */
             .putByte(opcode);
             label.put(this. - 1, false);
         }
         if ( != null) {
             if (nextInsn != null) {
                 // if the jump instruction is not a GOTO, the next instruction
                 // is also a successor of this instruction. Calling visitLabel
                 // adds the label of this next instruction as a successor of the
                 // current block, and starts a new basic block
                 visitLabel(nextInsn);
             }
             if (opcode == .) {
                 noSuccessor();
             }
         }
     }
 
     public void visitLabel(final Label label) {
         // resolves previous forward references to label, if any
          |= label.resolve(this..);
         // updates currentBlock
         if ((label.status & .) != 0) {
             return;
         }
         if ( == ) {
             if ( != null) {
                 if (label.position == .) {
                     // successive labels, do not start a new basic block
                     . |= (label.status & .);
                     label.frame = .;
                     return;
                 }
                 // ends current block (with one new successor)
                 addSuccessor(.label);
             }
             // begins a new current block
              = label;
             if (label.frame == null) {
                 label.frame = new Frame();
                 label.frame.owner = label;
             }
             // updates the basic block list
             if ( != null) {
                 if (label.position == .) {
                     . |= (label.status & .);
                     label.frame = .;
                      = ;
                     return;
                 }
                 . = label;
             }
              = label;
         } else if ( == ) {
             if ( != null) {
                 // ends current block (with one new successor)
                 . = ;
                 addSuccessor(label);
             }
             // begins a new current block
              = label;
             // resets the relative current and max stack sizes
              = 0;
              = 0;
             // updates the basic block list
             if ( != null) {
                 . = label;
             }
              = label;
         }
     }
    public void visitLdcInsn(final Object cst) {
        Item i = .newConstItem(cst);
        // Label currentBlock = this.currentBlock;
        if ( != null) {
            if ( == ) {
                ..execute(., 0, i);
            } else {
                int size;
                // computes the stack size variation
                if (i.type == . || i.type == .)
                {
                    size =  + 2;
                } else {
                    size =  + 1;
                }
                // updates current and max stack sizes
                if (size > ) {
                     = size;
                }
                 = size;
            }
        }
        // adds the instruction to the bytecode of the method
        int index = i.index;
        if (i.type == . || i.type == .) {
            .put12(20 /* LDC2_W */index);
        } else if (index >= 256) {
            .put12(19 /* LDC_W */index);
        } else {
            .put11(.index);
        }
    }
    public void visitIincInsn(final int varfinal int increment) {
        if ( != null) {
            if ( == ) {
                ..execute(.varnullnull);
            }
        }
        if ( != ) {
            // updates max locals
            int n = var + 1;
            if (n > ) {
                 = n;
            }
        }
        // adds the instruction to the bytecode of the method
        if ((var > 255) || (increment > 127) || (increment < -128)) {
            .putByte(196 /* WIDE */)
                    .put12(.var)
                    .putShort(increment);
        } else {
            .putByte(.).put11(varincrement);
        }
    }
    public void visitTableSwitchInsn(
        final int min,
        final int max,
        final Label dflt,
        final Label[] labels)
    {
        // adds the instruction to the bytecode of the method
        int source = .;
        . += (4 - . % 4) % 4;
        dflt.put(thissourcetrue);
        .putInt(min).putInt(max);
        for (int i = 0; i < labels.length; ++i) {
            labels[i].put(thissourcetrue);
        }
        // updates currentBlock
        visitSwitchInsn(dfltlabels);
    }
    public void visitLookupSwitchInsn(
        final Label dflt,
        final int[] keys,
        final Label[] labels)
    {
        // adds the instruction to the bytecode of the method
        int source = .;
        . += (4 - . % 4) % 4;
        dflt.put(thissourcetrue);
        .putInt(labels.length);
        for (int i = 0; i < labels.length; ++i) {
            .putInt(keys[i]);
            labels[i].put(thissourcetrue);
        }
        // updates currentBlock
        visitSwitchInsn(dfltlabels);
    }
    private void visitSwitchInsn(final Label dfltfinal Label[] labels) {
        // Label currentBlock = this.currentBlock;
        if ( != null) {
            if ( == ) {
                ..execute(., 0, nullnull);
                // adds current block successors
                addSuccessor(.dflt);
                dflt.getFirst(). |= .;
                for (int i = 0; i < labels.length; ++i) {
                    addSuccessor(.labels[i]);
                    labels[i].getFirst(). |= .;
                }
            } else {
                // updates current stack size (max stack size unchanged)
                --;
                // adds current block successors
                addSuccessor(dflt);
                for (int i = 0; i < labels.length; ++i) {
                    addSuccessor(labels[i]);
                }
            }
            // ends current block
            noSuccessor();
        }
    }
    public void visitMultiANewArrayInsn(final String descfinal int dims) {
        Item i = .newClassItem(desc);
        // Label currentBlock = this.currentBlock;
        if ( != null) {
            if ( == ) {
                ..execute(.dimsi);
            } else {
                // updates current stack size (max stack size unchanged because
                // stack size variation always negative or null)
                 += 1 - dims;
            }
        }
        // adds the instruction to the bytecode of the method
        .put12(.i.index).putByte(dims);
    }
    public void visitTryCatchBlock(
        final Label start,
        final Label end,
        final Label handler,
        final String type)
    {
        ++;
        Handler h = new Handler();
        h.start = start;
        h.end = end;
        h.handler = handler;
        h.desc = type;
        h.type = type != null ? .newClass(type) : 0;
        if ( == null) {
             = h;
        } else {
            . = h;
        }
         = h;
    }
    public void visitLocalVariable(
        final String name,
        final String desc,
        final String signature,
        final Label start,
        final Label end,
        final int index)
    {
        if (signature != null) {
            if ( == null) {
                 = new ByteVector();
            }
            ++;
            .putShort(start.position)
                    .putShort(end.position - start.position)
                    .putShort(.newUTF8(name))
                    .putShort(.newUTF8(signature))
                    .putShort(index);
        }
        if ( == null) {
             = new ByteVector();
        }
        ++;
        .putShort(start.position)
                .putShort(end.position - start.position)
                .putShort(.newUTF8(name))
                .putShort(.newUTF8(desc))
                .putShort(index);
        if ( != ) {
            // updates max locals
            char c = desc.charAt(0);
            int n = index + (c == 'J' || c == 'D' ? 2 : 1);
            if (n > ) {
                 = n;
            }
        }
    }
    public void visitLineNumber(final int linefinal Label start) {
        if ( == null) {
             = new ByteVector();
        }
        ++;
        .putShort(start.position);
        .putShort(line);
    }
    public void visitMaxs(final int maxStackfinal int maxLocals) {
        if (. &&  == ) {
            // completes the control flow graph with exception handler blocks
            Handler handler = ;
            while (handler != null) {
                Label l = handler.start.getFirst();
                Label h = handler.handler.getFirst();
                Label e = handler.end.getFirst();
                // computes the kind of the edges to 'h'
                String t = handler.desc == null
                        ? "java/lang/Throwable"
                        : handler.desc;
                int kind = . | .addType(t);
                // h is an exception handler
                h.status |= .;
                // adds 'h' as a successor of labels between 'start' and 'end'
                while (l != e) {
                    // creates an edge to 'h'
                    Edge b = new Edge();
                    b.info = kind;
                    b.successor = h;
                    // adds it to the successors of 'l'
                    b.next = l.successors;
                    l.successors = b;
                    // goes to the next label
                    l = l.successor;
                }
                handler = handler.next;
            }
            // creates and visits the first (implicit) frame
            Frame f = .;
            Type[] args = Type.getArgumentTypes();
            f.initInputFrame(argsthis.);
            visitFrame(f);
            /*