Home | History | Annotate | Download | only in attrs
      1 /**
      2  * ASM: a very small and fast Java bytecode manipulation framework
      3  * Copyright (c) 2000-2005 INRIA, France Telecom
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the copyright holders nor the names of its
     15  *    contributors may be used to endorse or promote products derived from
     16  *    this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     28  * THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 package org.objectweb.asm.attrs;
     31 
     32 import java.util.ArrayList;
     33 import java.util.Collections;
     34 import java.util.List;
     35 
     36 import org.objectweb.asm.Attribute;
     37 import org.objectweb.asm.ByteVector;
     38 import org.objectweb.asm.ClassReader;
     39 import org.objectweb.asm.ClassWriter;
     40 import org.objectweb.asm.Label;
     41 import org.objectweb.asm.Opcodes;
     42 import org.objectweb.asm.Type;
     43 
     44 /**
     45  * The stack map attribute is used during the process of verification by
     46  * typechecking (&sect;4.11.1). <br> <br> A stack map attribute consists of zero or
     47  * more stack map frames. Each stack map frame specifies (either explicitly or
     48  * implicitly) a bytecode offset, the verification types (&sect;4.11.1) for the local
     49  * variables, and the verification types for the operand stack. <br> <br> The
     50  * type checker deals with and manipulates the expected types of a method's
     51  * local variables and operand stack. Throughout this section, a location refers
     52  * to either a single local variable or to a single operand stack entry. <br>
     53  * <br> We will use the terms stack frame map and type state interchangeably to
     54  * describe a mapping from locations in the operand stack and local variables of
     55  * a method to verification types. We will usually use the term stack frame map
     56  * when such a mapping is provided in the class file, and the term type state
     57  * when the mapping is inferred by the type checker. <br> <br> If a method's
     58  * Code attribute does not have a StackMapTable attribute, it has an implicit
     59  * stack map attribute. This implicit stack map attribute is equivalent to a
     60  * StackMapTable attribute with number_of_entries equal to zero. A method's Code
     61  * attribute may have at most one StackMapTable attribute, otherwise a
     62  * java.lang.ClassFormatError is thrown. <br> <br> The format of the stack map
     63  * in the class file is given below. In the following, if the length of the
     64  * method's byte code is 65535 or less, then uoffset represents the type u2;
     65  * otherwise uoffset represents the type u4. If the maximum number of local
     66  * variables for the method is 65535 or less, then <code>ulocalvar</code>
     67  * represents the type u2; otherwise ulocalvar represents the type u4. If the
     68  * maximum size of the operand stack is 65535 or less, then <code>ustack</code>
     69  * represents the type u2; otherwise ustack represents the type u4.
     70  *
     71  * <pre>
     72  * stack_map { // attribute StackMapTable
     73  *   u2 attribute_name_index;
     74  *   u4 attribute_length
     75  *   uoffset number_of_entries;
     76  *   stack_map_frame entries[number_of_entries];
     77  * }
     78  * </pre>
     79  *
     80  * Each stack_map_frame structure specifies the type state at a particular byte
     81  * code offset. Each frame type specifies (explicitly or implicitly) a value,
     82  * offset_delta, that is used to calulate the actual byte code offset at which
     83  * it applies. The byte code offset at which the frame applies is given by
     84  * adding <code>1 + offset_delta</code> to the <code>offset</code> of the
     85  * previous frame, unless the previous frame is the initial frame of the method,
     86  * in which case the byte code offset is <code>offset_delta</code>. <br> <br>
     87  * <i>Note that the length of the byte codes is not the same as the length of
     88  * the Code attribute. The byte codes are embedded in the Code attribute, along
     89  * with other information.</i> <br> <br> By using an offset delta rather than
     90  * the actual byte code offset we ensure, by definition, that stack map frames
     91  * are in the correctly sorted order. Furthermore, by consistently using the
     92  * formula <code>offset_delta + 1</code> for all explicit frames, we guarantee
     93  * the absence of duplicates. <br> <br> All frame types, even full_frame, rely
     94  * on the previous frame for some of their semantics. This raises the question
     95  * of what is the very first frame? The initial frame is implicit, and computed
     96  * from the method descriptor. See the Prolog code for methodInitialStacFrame.
     97  * <br> <br> The stack_map_frame structure consists of a one-byte tag followed
     98  * by zero or more bytes, giving more information, depending upon the tag. <br>
     99  * <br> A stack map frame may belong to one of several frame types
    100  *
    101  * <pre>
    102  * union stack_map_frame {
    103  *   same_frame;
    104  *   same_locals_1_stack_item_frame;
    105  *   chop_frame;
    106  *   same_frame_extended;
    107  *   append_frame;
    108  *   full_frame;
    109  * }
    110  * </pre>
    111  *
    112  * The frame type same_frame is represented by tags in the range [0-63]. If the
    113  * frame type is same_frame, it means the frame has exactly the same locals as
    114  * the previous stack map frame and that the number of stack items is zero. The
    115  * offset_delta value for the frame is the value of the tag field, frame_type.
    116  * The form of such a frame is then:
    117  *
    118  * <pre>
    119  * same_frame {
    120  *   u1 frame_type = SAME;  // 0-63
    121  * }
    122  * </pre>
    123  *
    124  * The frame type same_locals_1_stack_item_frame is represented by tags in the
    125  * range [64, 127]. If the frame_type is same_locals_1_stack_item_frame, it
    126  * means the frame has exactly the same locals as the previous stack map frame
    127  * and that the number of stack items is 1. The offset_delta value for the frame
    128  * is the value (frame_type - 64). There is a verification_type_info following
    129  * the frame_type for the one stack item. The form of such a frame is then:
    130  *
    131  * <pre>
    132  * same_locals_1_stack_item_frame {
    133  *   u1 frame_type = SAME_LOCALS_1_STACK_ITEM;  // 64-127
    134  *    verification_type_info stack[1];
    135  * }
    136  * </pre>
    137  *
    138  * Tags in the range [128-247] are reserved for future use. <br> <br> The frame
    139  * type chop_frame is represented by tags in the range [248-250]. If the
    140  * frame_type is chop_frame, it means that the current locals are the same as
    141  * the locals in the previous frame, except that the k last locals are absent.
    142  * The value of k is given by the formula 251-frame_type. <br> <br> The form of
    143  * such a frame is then:
    144  *
    145  * <pre>
    146  * chop_frame {
    147  *   u1 frame_type=CHOP;  // 248-250
    148  *   uoffset offset_delta;
    149  * }
    150  * </pre>
    151  *
    152  * The frame type same_frame_extended is represented by the tag value 251. If
    153  * the frame type is same_frame_extended, it means the frame has exactly the
    154  * same locals as the previous stack map frame and that the number of stack
    155  * items is zero. The form of such a frame is then:
    156  *
    157  * <pre>
    158  * same_frame_extended {
    159  *   u1 frame_type = SAME_FRAME_EXTENDED;  // 251
    160  *   uoffset offset_delta;
    161  * }
    162  * </pre>
    163  *
    164  * The frame type append_frame is represented by tags in the range [252-254]. If
    165  * the frame_type is append_frame, it means that the current locals are the same
    166  * as the locals in the previous frame, except that k additional locals are
    167  * defined. The value of k is given by the formula frame_type-251. <br> <br> The
    168  * form of such a frame is then:
    169  *
    170  * <pre>
    171  * append_frame {
    172  *   u1 frame_type =APPEND;  // 252-254
    173  *   uoffset offset_delta;
    174  *   verification_type_info locals[frame_type -251];
    175  * }
    176  * </pre>
    177  *
    178  * The 0th entry in locals represents the type of the first additional local
    179  * variable. If locals[M] represents local variable N, then locals[M+1]
    180  * represents local variable N+1 if locals[M] is one of Top_variable_info,
    181  * Integer_variable_info, Float_variable_info, Null_variable_info,
    182  * UninitializedThis_variable_info, Object_variable_info, or
    183  * Uninitialized_variable_info, otherwise locals[M+1] represents local variable
    184  * N+2. It is an error if, for any index i, locals[i] represents a local
    185  * variable whose index is greater than the maximum number of local variables
    186  * for the method. <br> <br> The frame type full_frame is represented by the tag
    187  * value 255. The form of such a frame is then:
    188  *
    189  * <pre>
    190  * full_frame {
    191  *   u1 frame_type = FULL_FRAME;  // 255
    192  *   uoffset offset_delta;
    193  *   ulocalvar number_of_locals;
    194  *   verification_type_info locals[number_of_locals];
    195  *   ustack number_of_stack_items;
    196  *   verification_type_info stack[number_of_stack_items];
    197  * }
    198  * </pre>
    199  *
    200  * The 0th entry in locals represents the type of local variable 0. If locals[M]
    201  * represents local variable N, then locals[M+1] represents local variable N+1
    202  * if locals[M] is one of Top_variable_info, Integer_variable_info,
    203  * Float_variable_info, Null_variable_info, UninitializedThis_variable_info,
    204  * Object_variable_info, or Uninitialized_variable_info, otherwise locals[M+1]
    205  * represents local variable N+2. It is an error if, for any index i, locals[i]
    206  * represents a local variable whose index is greater than the maximum number of
    207  * local variables for the method. <br> <br> The 0th entry in stack represents
    208  * the type of the bottom of the stack, and subsequent entries represent types
    209  * of stack elements closer to the top of the operand stack. We shall refer to
    210  * the bottom element of the stack as stack element 0, and to subsequent
    211  * elements as stack element 1, 2 etc. If stack[M] represents stack element N,
    212  * then stack[M+1] represents stack element N+1 if stack[M] is one of
    213  * Top_variable_info, Integer_variable_info, Float_variable_info,
    214  * Null_variable_info, UninitializedThis_variable_info, Object_variable_info, or
    215  * Uninitialized_variable_info, otherwise stack[M+1] represents stack element
    216  * N+2. It is an error if, for any index i, stack[i] represents a stack entry
    217  * whose index is greater than the maximum operand stack size for the method.
    218  * <br> <br> We say that an instruction in the byte code has a corresponding
    219  * stack map frame if the offset in the offset field of the stack map frame is
    220  * the same as the offset of the instruction in the byte codes. <br> <br> The
    221  * verification_type_info structure consists of a one-byte tag followed by zero
    222  * or more bytes, giving more information about the tag. Each
    223  * verification_type_info structure specifies the verification type of one or
    224  * two locations.
    225  *
    226  * <pre>
    227  * union verification_type_info {
    228  *   Top_variable_info;
    229  *   Integer_variable_info;
    230  *   Float_variable_info;
    231  *   Long_variable_info;
    232  *   Double_variable_info;
    233  *   Null_variable_info;
    234  *   UninitializedThis_variable_info;
    235  *   Object_variable_info;
    236  *   Uninitialized_variable_info;
    237  * }
    238  * </pre>
    239  *
    240  * The Top_variable_info type indicates that the local variable has the
    241  * verification type top (T.)
    242  *
    243  * <pre>
    244  * Top_variable_info {
    245  *   u1 tag = ITEM_Top; // 0
    246  * }
    247  * </pre>
    248  *
    249  * The Integer_variable_info type indicates that the location contains the
    250  * verification type int.
    251  *
    252  * <pre>
    253  * Integer_variable_info {
    254  *   u1 tag = ITEM_Integer; // 1
    255  * }
    256  * </pre>
    257  *
    258  * The Float_variable_info type indicates that the location contains the
    259  * verification type float.
    260  *
    261  * <pre>
    262  * Float_variable_info {
    263  *   u1 tag = ITEM_Float; // 2
    264  * }
    265  * </pre>
    266  *
    267  * The Long_variable_info type indicates that the location contains the
    268  * verification type long. If the location is a local variable, then:
    269  *
    270  * <ul> <li>It must not be the local variable with the highest index.</li>
    271  * <li>The next higher numbered local variable contains the verification type
    272  * T.</li> </ul>
    273  *
    274  * If the location is an operand stack entry, then:
    275  *
    276  * <ul> <li>The current location must not be the topmost location of the
    277  * operand stack.</li> <li>the next location closer to the top of the operand
    278  * stack contains the verification type T.</li> </ul>
    279  *
    280  * This structure gives the contents of two locations in the operand stack or in
    281  * the local variables.
    282  *
    283  * <pre>
    284  * Long_variable_info {
    285  *   u1 tag = ITEM_Long; // 4
    286  * }
    287  * </pre>
    288  *
    289  * The Double_variable_info type indicates that the location contains the
    290  * verification type double. If the location is a local variable, then:
    291  *
    292  * <ul> <li>It must not be the local variable with the highest index.</li>
    293  * <li>The next higher numbered local variable contains the verification type
    294  * T. <li> </ul>
    295  *
    296  * If the location is an operand stack entry, then:
    297  *
    298  * <ul> <li>The current location must not be the topmost location of the
    299  * operand stack.</li> <li>the next location closer to the top of the operand
    300  * stack contains the verification type T.</li> </ul>
    301  *
    302  * This structure gives the contents of two locations in in the operand stack or
    303  * in the local variables.
    304  *
    305  * <pre>
    306  * Double_variable_info {
    307  *   u1 tag = ITEM_Double; // 3
    308  * }
    309  * </pre>
    310  *
    311  * The Null_variable_info type indicates that location contains the verification
    312  * type null.
    313  *
    314  * <pre>
    315  * Null_variable_info {
    316  *   u1 tag = ITEM_Null; // 5
    317  * }
    318  * </pre>
    319  *
    320  * The UninitializedThis_variable_info type indicates that the location contains
    321  * the verification type uninitializedThis.
    322  *
    323  * <pre>
    324  * UninitializedThis_variable_info {
    325  *   u1 tag = ITEM_UninitializedThis; // 6
    326  * }
    327  * </pre>
    328  *
    329  * The Object_variable_info type indicates that the location contains an
    330  * instance of the class referenced by the constant pool entry.
    331  *
    332  * <pre>
    333  * Object_variable_info {
    334  *   u1 tag = ITEM_Object; // 7
    335  *   u2 cpool_index;
    336  * }
    337  * </pre>
    338  *
    339  * The Uninitialized_variable_info indicates that the location contains the
    340  * verification type uninitialized(offset). The offset item indicates the offset
    341  * of the new instruction that created the object being stored in the location.
    342  *
    343  * <pre>
    344  * Uninitialized_variable_info {
    345  *   u1 tag = ITEM_Uninitialized // 8
    346  *   uoffset offset;
    347  * }
    348  * </pre>
    349  *
    350  * @see "ClassFileFormat-Java6.fm Page 138 Friday, April 15, 2005 3:22 PM"
    351  *
    352  * @author Eugene Kuleshov
    353  */
    354 public class StackMapTableAttribute extends Attribute {
    355     /**
    356      * Frame has exactly the same locals as the previous stack map frame and
    357      * number of stack items is zero.
    358      */
    359     public static final int SAME_FRAME = 0; // to 63 (0-3f)
    360 
    361     /**
    362      * Frame has exactly the same locals as the previous stack map frame and
    363      * number of stack items is 1
    364      */
    365     public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127
    366 
    367     // (40-7f)
    368 
    369     /**
    370      * Reserved for future use
    371      */
    372     public static final int RESERVED = 128;
    373 
    374     /**
    375      * Frame has exactly the same locals as the previous stack map frame and
    376      * number of stack items is 1. Offset is bigger then 63;
    377      */
    378     public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
    379 
    380     /**
    381      * Frame where current locals are the same as the locals in the previous
    382      * frame, except that the k last locals are absent. The value of k is given
    383      * by the formula 251-frame_type.
    384      */
    385     public static final int CHOP_FRAME = 248; // to 250 (f8-fA)
    386 
    387     /**
    388      * Frame has exactly the same locals as the previous stack map frame and
    389      * number of stack items is zero. Offset is bigger then 63;
    390      */
    391     public static final int SAME_FRAME_EXTENDED = 251; // fb
    392 
    393     /**
    394      * Frame where current locals are the same as the locals in the previous
    395      * frame, except that k additional locals are defined. The value of k is
    396      * given by the formula frame_type-251.
    397      */
    398     public static final int APPEND_FRAME = 252; // to 254 // fc-fe
    399 
    400     /**
    401      * Full frame
    402      */
    403     public static final int FULL_FRAME = 255; // ff
    404 
    405     private static final int MAX_SHORT = 65535;
    406 
    407     /**
    408      * A <code>List</code> of <code>StackMapFrame</code> instances.
    409      */
    410     private List frames;
    411 
    412     public StackMapTableAttribute() {
    413         super("StackMapTable");
    414     }
    415 
    416     public StackMapTableAttribute(List frames) {
    417         this();
    418         this.frames = frames;
    419     }
    420 
    421     public List getFrames() {
    422         return frames;
    423     }
    424 
    425     public StackMapFrame getFrame(Label label) {
    426         for (int i = 0; i < frames.size(); i++) {
    427             StackMapFrame frame = (StackMapFrame) frames.get(i);
    428             if (frame.label == label) {
    429                 return frame;
    430             }
    431         }
    432         return null;
    433     }
    434 
    435     public boolean isUnknown() {
    436         return false;
    437     }
    438 
    439     public boolean isCodeAttribute() {
    440         return true;
    441     }
    442 
    443     protected Attribute read(
    444         ClassReader cr,
    445         int off,
    446         int len,
    447         char[] buf,
    448         int codeOff,
    449         Label[] labels)
    450     {
    451 
    452         ArrayList frames = new ArrayList();
    453 
    454         // note that this is not the size of Code attribute
    455         boolean isExtCodeSize = cr.readInt(codeOff + 4) > MAX_SHORT;
    456         boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > MAX_SHORT;
    457         boolean isExtStack = cr.readUnsignedShort(codeOff) > MAX_SHORT;
    458 
    459         int offset = 0;
    460 
    461         int methodOff = getMethodOff(cr, codeOff, buf);
    462         StackMapFrame frame = new StackMapFrame(getLabel(offset, labels),
    463                 calculateLocals(cr.readClass(cr.header + 2, buf), // owner
    464                         cr.readUnsignedShort(methodOff), // method access
    465                         cr.readUTF8(methodOff + 2, buf), // method name
    466                         cr.readUTF8(methodOff + 4, buf)), // method desc
    467                 Collections.EMPTY_LIST);
    468         frames.add(frame);
    469 
    470         // System.err.println( cr.readUTF8( methodOff + 2, buf));
    471         // System.err.println( offset +" delta:" + 0 +" : "+ frame);
    472 
    473         int size;
    474         if (isExtCodeSize) {
    475             size = cr.readInt(off);
    476             off += 4;
    477         } else {
    478             size = cr.readUnsignedShort(off);
    479             off += 2;
    480         }
    481 
    482         for (; size > 0; size--) {
    483             int tag = cr.readByte(off); // & 0xff;
    484             off++;
    485 
    486             List stack;
    487             List locals;
    488 
    489             int offsetDelta;
    490             if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) {  // SAME_FRAME
    491                 offsetDelta = tag;
    492 
    493                 locals = new ArrayList(frame.locals);
    494                 stack = Collections.EMPTY_LIST;
    495 
    496             } else if (tag < RESERVED) {  // SAME_LOCALS_1_STACK_ITEM_FRAME
    497                 offsetDelta = tag - SAME_LOCALS_1_STACK_ITEM_FRAME;
    498 
    499                 locals = new ArrayList(frame.locals);
    500                 stack = new ArrayList();
    501                 // read verification_type_info stack[1];
    502                 off = readType(stack, isExtCodeSize, cr, off, labels, buf);
    503 
    504             } else {
    505                 if (isExtCodeSize) {
    506                     offsetDelta = cr.readInt(off);
    507                     off += 4;
    508                 } else {
    509                     offsetDelta = cr.readUnsignedShort(off);
    510                     off += 2;
    511                 }
    512 
    513                 if (tag == SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {  // SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
    514                     locals = new ArrayList(frame.locals);
    515                     stack = new ArrayList();
    516                     // read verification_type_info stack[1];
    517                     off = readType(stack, isExtCodeSize, cr, off, labels, buf);
    518 
    519                 } else if (tag >= CHOP_FRAME && tag < SAME_FRAME_EXTENDED) {  // CHOP_FRAME
    520                     stack = Collections.EMPTY_LIST;
    521 
    522                     int k = SAME_FRAME_EXTENDED - tag;
    523                     // copy locals from prev frame and chop last k
    524                     locals = new ArrayList(frame.locals.subList(0,
    525                             frame.locals.size() - k));
    526 
    527                 } else if (tag == SAME_FRAME_EXTENDED) {  // SAME_FRAME_EXTENDED
    528                     stack = Collections.EMPTY_LIST;
    529                     locals = new ArrayList(frame.locals);
    530 
    531                 } else if ( /* tag>=APPEND && */tag < FULL_FRAME) {  // APPEND_FRAME
    532                     stack = Collections.EMPTY_LIST;
    533 
    534                     // copy locals from prev frame and append new k
    535                     locals = new ArrayList(frame.locals);
    536                     for (int k = tag - SAME_FRAME_EXTENDED; k > 0; k--) {
    537                         off = readType(locals,
    538                                 isExtCodeSize,
    539                                 cr,
    540                                 off,
    541                                 labels,
    542                                 buf);
    543                     }
    544 
    545                 } else if (tag == FULL_FRAME) {  // FULL_FRAME
    546                     // read verification_type_info locals[number_of_locals];
    547                     locals = new ArrayList();
    548                     off = readTypes(locals,
    549                             isExtLocals,
    550                             isExtCodeSize,
    551                             cr,
    552                             off,
    553                             labels,
    554                             buf);
    555 
    556                     // read verification_type_info stack[number_of_stack_items];
    557                     stack = new ArrayList();
    558                     off = readTypes(stack,
    559                             isExtStack,
    560                             isExtCodeSize,
    561                             cr,
    562                             off,
    563                             labels,
    564                             buf);
    565 
    566                 } else {
    567                     throw new RuntimeException("Unknown frame type " + tag
    568                             + " after offset " + offset);
    569 
    570                 }
    571             }
    572 
    573             offset += offsetDelta;
    574 
    575             Label offsetLabel = getLabel(offset, labels);
    576 
    577             frame = new StackMapFrame(offsetLabel, locals, stack);
    578             frames.add(frame);
    579             // System.err.println( tag +" " + offset +" delta:" + offsetDelta +
    580             // " frameType:"+ frameType+" : "+ frame);
    581 
    582             offset++;
    583         }
    584 
    585         return new StackMapTableAttribute(frames);
    586     }
    587 
    588     protected ByteVector write(
    589         ClassWriter cw,
    590         byte[] code,
    591         int len,
    592         int maxStack,
    593         int maxLocals)
    594     {
    595         ByteVector bv = new ByteVector();
    596         // TODO verify this value (MAX_SHORT)
    597         boolean isExtCodeSize = code != null && code.length > MAX_SHORT;
    598         writeSize(frames.size() - 1, bv, isExtCodeSize);
    599 
    600         if (frames.size() < 2) {
    601             return bv;
    602         }
    603 
    604         boolean isExtLocals = maxLocals > MAX_SHORT;
    605         boolean isExtStack = maxStack > MAX_SHORT;
    606 
    607         // skip the first frame
    608         StackMapFrame frame = (StackMapFrame) frames.get(0);
    609         List locals = frame.locals;
    610         int offset = frame.label.getOffset();
    611 
    612         for (int i = 1; i < frames.size(); i++) {
    613             frame = (StackMapFrame) frames.get(i);
    614 
    615             List clocals = frame.locals;
    616             List cstack = frame.stack;
    617             int coffset = frame.label.getOffset();
    618 
    619             int clocalsSize = clocals.size();
    620             int cstackSize = cstack.size();
    621 
    622             int localsSize = locals.size();
    623 
    624             int delta = coffset - offset;
    625 
    626             int type = FULL_FRAME;
    627             int k = 0;
    628             if (cstackSize == 0) {
    629                 k = clocalsSize - localsSize;
    630                 switch (k) {
    631                     case -3:
    632                     case -2:
    633                     case -1:
    634                         type = CHOP_FRAME; // CHOP or FULL
    635                         localsSize = clocalsSize; // for full_frame check
    636                         break;
    637 
    638                     case 0:
    639                         // SAME, SAME_EXTENDED or FULL
    640                         type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
    641                         break;
    642 
    643                     case 1:
    644                     case 2:
    645                     case 3:
    646                         type = APPEND_FRAME; // APPEND or FULL
    647                         break;
    648                 }
    649             } else if (localsSize == clocalsSize && cstackSize == 1) {
    650                 // SAME_LOCAL_1_STACK or FULL
    651                 type = delta < 63
    652                         ? SAME_LOCALS_1_STACK_ITEM_FRAME
    653                         : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
    654             }
    655 
    656             if (type != FULL_FRAME) {
    657                 // verify if stack and locals are the same
    658                 for (int j = 0; j < localsSize && type != FULL_FRAME; j++) {
    659                     if (!locals.get(j).equals(clocals.get(j)))
    660                         type = FULL_FRAME;
    661                 }
    662             }
    663 
    664             switch (type) {
    665                 case SAME_FRAME:
    666                     bv.putByte(delta);
    667                     break;
    668 
    669                 case SAME_LOCALS_1_STACK_ITEM_FRAME:
    670                     bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
    671                     writeTypeInfos(bv, cw, cstack, 0, 1);
    672                     break;
    673 
    674                 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
    675                     bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED);
    676                     writeSize(delta, bv, isExtCodeSize);
    677                     writeTypeInfos(bv, cw, cstack, 0, 1);
    678                     break;
    679 
    680                 case SAME_FRAME_EXTENDED:
    681                     bv.putByte(SAME_FRAME_EXTENDED);
    682                     writeSize(delta, bv, isExtCodeSize);
    683                     break;
    684 
    685                 case CHOP_FRAME:
    686                     bv.putByte(SAME_FRAME_EXTENDED + k); // negative k
    687                     writeSize(delta, bv, isExtCodeSize);
    688                     break;
    689 
    690                 case APPEND_FRAME:
    691                     bv.putByte(SAME_FRAME_EXTENDED + k); // positive k
    692                     writeSize(delta, bv, isExtCodeSize);
    693                     writeTypeInfos(bv,
    694                             cw,
    695                             clocals,
    696                             clocalsSize - 1,
    697                             clocalsSize);
    698                     break;
    699 
    700                 case FULL_FRAME:
    701                     bv.putByte(FULL_FRAME);
    702                     writeSize(delta, bv, isExtCodeSize);
    703                     writeSize(clocalsSize, bv, isExtLocals);
    704                     writeTypeInfos(bv, cw, clocals, 0, clocalsSize);
    705                     writeSize(cstackSize, bv, isExtStack);
    706                     writeTypeInfos(bv, cw, cstack, 0, cstackSize);
    707                     break;
    708 
    709                 default:
    710                     throw new RuntimeException();
    711             }
    712             offset = coffset + 1; // compensating non first offset
    713             locals = clocals;
    714         }
    715         return bv;
    716     }
    717 
    718     private void writeSize(int delta, ByteVector bv, boolean isExt) {
    719         if (isExt) {
    720             bv.putInt(delta);
    721         } else {
    722             bv.putShort(delta);
    723         }
    724     }
    725 
    726     private void writeTypeInfos(
    727         ByteVector bv,
    728         ClassWriter cw,
    729         List info,
    730         int start,
    731         int end)
    732     {
    733         for (int j = start; j < end; j++) {
    734             StackMapType typeInfo = (StackMapType) info.get(j);
    735             bv.putByte(typeInfo.getType());
    736 
    737             switch (typeInfo.getType()) {
    738                 case StackMapType.ITEM_Object: //
    739                     bv.putShort(cw.newClass(typeInfo.getObject()));
    740                     break;
    741 
    742                 case StackMapType.ITEM_Uninitialized: //
    743                     bv.putShort(typeInfo.getLabel().getOffset());
    744                     break;
    745 
    746             }
    747         }
    748     }
    749 
    750     public static int getMethodOff(ClassReader cr, int codeOff, char[] buf) {
    751         int off = cr.header + 6;
    752 
    753         int interfacesCount = cr.readUnsignedShort(off);
    754         off += 2 + interfacesCount * 2;
    755 
    756         int fieldsCount = cr.readUnsignedShort(off);
    757         off += 2;
    758         for (; fieldsCount > 0; --fieldsCount) {
    759             int attrCount = cr.readUnsignedShort(off + 6); // field attributes
    760             off += 8;
    761             for (; attrCount > 0; --attrCount) {
    762                 off += 6 + cr.readInt(off + 2);
    763             }
    764         }
    765 
    766         int methodsCount = cr.readUnsignedShort(off);
    767         off += 2;
    768         for (; methodsCount > 0; --methodsCount) {
    769             int methodOff = off;
    770             int attrCount = cr.readUnsignedShort(off + 6); // method attributes
    771             off += 8;
    772             for (; attrCount > 0; --attrCount) {
    773                 String attrName = cr.readUTF8(off, buf);
    774                 off += 6;
    775                 if (attrName.equals("Code")) {
    776                     if (codeOff == off) {
    777                         return methodOff;
    778                     }
    779                 }
    780                 off += cr.readInt(off - 4);
    781             }
    782         }
    783 
    784         return -1;
    785     }
    786 
    787     /**
    788      * Use method signature and access flags to resolve initial locals state.
    789      *
    790      * @param className name of the method's owner class.
    791      * @param access access flags of the method.
    792      * @param methodName name of the method.
    793      * @param methodDesc descriptor of the method.
    794      * @return list of <code>StackMapType</code> instances representing locals
    795      *         for an initial frame.
    796      */
    797     public static List calculateLocals(
    798         String className,
    799         int access,
    800         String methodName,
    801         String methodDesc)
    802     {
    803         List locals = new ArrayList();
    804 
    805         // TODO
    806         if ("<init>".equals(methodName)
    807                 && !className.equals("java/lang/Object"))
    808         {
    809             StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_UninitializedThis);
    810             typeInfo.setObject(className); // this
    811             locals.add(typeInfo);
    812         } else if ((access & Opcodes.ACC_STATIC) == 0) {
    813             StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_Object);
    814             typeInfo.setObject(className); // this
    815             locals.add(typeInfo);
    816         }
    817 
    818         Type[] types = Type.getArgumentTypes(methodDesc);
    819         for (int i = 0; i < types.length; i++) {
    820             Type t = types[i];
    821             StackMapType smt;
    822             switch (t.getSort()) {
    823                 case Type.LONG:
    824                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long);
    825                     break;
    826                 case Type.DOUBLE:
    827                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Double);
    828                     break;
    829 
    830                 case Type.FLOAT:
    831                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float);
    832                     break;
    833 
    834                 case Type.ARRAY:
    835                 case Type.OBJECT:
    836                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Object);
    837                     smt.setObject(t.getDescriptor()); // TODO verify name
    838                     break;
    839 
    840                 default:
    841                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Integer);
    842                     break;
    843             }
    844         }
    845 
    846         return locals;
    847     }
    848 
    849     private int readTypes(
    850         List info,
    851         boolean isExt,
    852         boolean isExtCodeSize,
    853         ClassReader cr,
    854         int off,
    855         Label[] labels,
    856         char[] buf)
    857     {
    858         int n = 0;
    859         if (isExt) {
    860             n = cr.readInt(off);
    861             off += 4;
    862         } else {
    863             n = cr.readUnsignedShort(off);
    864             off += 2;
    865         }
    866 
    867         for (; n > 0; n--) {
    868             off = readType(info, isExtCodeSize, cr, off, labels, buf);
    869         }
    870         return off;
    871     }
    872 
    873     private int readType(
    874         List info,
    875         boolean isExtCodeSize,
    876         ClassReader cr,
    877         int off,
    878         Label[] labels,
    879         char[] buf)
    880     {
    881         int itemType = cr.readByte(off++);
    882         StackMapType typeInfo = StackMapType.getTypeInfo(itemType);
    883         info.add(typeInfo);
    884         switch (itemType) {
    885             // case StackMapType.ITEM_Long: //
    886             // case StackMapType.ITEM_Double: //
    887             // info.add(StackMapType.getTypeInfo(StackMapType.ITEM_Top));
    888             // break;
    889 
    890             case StackMapType.ITEM_Object: //
    891                 typeInfo.setObject(cr.readClass(off, buf));
    892                 off += 2;
    893                 break;
    894 
    895             case StackMapType.ITEM_Uninitialized: //
    896                 int offset;
    897                 if (isExtCodeSize) {
    898                     offset = cr.readInt(off);
    899                     off += 4;
    900                 } else {
    901                     offset = cr.readUnsignedShort(off);
    902                     off += 2;
    903                 }
    904 
    905                 typeInfo.setLabel(getLabel(offset, labels));
    906                 break;
    907         }
    908         return off;
    909     }
    910 
    911     private Label getLabel(int offset, Label[] labels) {
    912         Label l = labels[offset];
    913         if (l != null) {
    914             return l;
    915         }
    916         return labels[offset] = new Label();
    917     }
    918 
    919     public String toString() {
    920         StringBuffer sb = new StringBuffer("StackMapTable[");
    921         for (int i = 0; i < frames.size(); i++) {
    922             sb.append('\n').append('[').append(frames.get(i)).append(']');
    923         }
    924         sb.append("\n]");
    925         return sb.toString();
    926     }
    927 }
    928