KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > asm > attrs > StackMapTableAttribute


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 JavaDoc;
33 import java.util.Collections JavaDoc;
34 import java.util.List JavaDoc;
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 (§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 (§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 JavaDoc frames;
411
412     public StackMapTableAttribute() {
413         super("StackMapTable");
414     }
415
416     public StackMapTableAttribute(List JavaDoc frames) {
417         this();
418         this.frames = frames;
419     }
420
421     public List JavaDoc 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 JavaDoc frames = new ArrayList JavaDoc();
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 JavaDoc stack;
487             List JavaDoc locals;
488
489             int offsetDelta;
490             int frameType;
491             if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) {
492                 frameType = SAME_FRAME;
493                 offsetDelta = tag;
494
495                 locals = new ArrayList JavaDoc(frame.locals);
496                 stack = Collections.EMPTY_LIST;
497
498             } else if (tag < RESERVED) {
499                 frameType = SAME_LOCALS_1_STACK_ITEM_FRAME;
500                 offsetDelta = tag - SAME_LOCALS_1_STACK_ITEM_FRAME;
501
502                 locals = new ArrayList JavaDoc(frame.locals);
503                 stack = new ArrayList JavaDoc();
504                 // read verification_type_info stack[1];
505
off = readType(stack, isExtCodeSize, cr, off, labels, buf);
506
507             } else {
508                 if (isExtCodeSize) {
509                     offsetDelta = cr.readInt(off);
510                     off += 4;
511                 } else {
512                     offsetDelta = cr.readUnsignedShort(off);
513                     off += 2;
514                 }
515
516                 if (tag == SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
517                     frameType = SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
518                     locals = new ArrayList JavaDoc(frame.locals);
519                     stack = new ArrayList JavaDoc();
520                     // read verification_type_info stack[1];
521
off = readType(stack, isExtCodeSize, cr, off, labels, buf);
522
523                 } else if (tag >= CHOP_FRAME && tag < SAME_FRAME_EXTENDED) {
524                     frameType = CHOP_FRAME;
525                     stack = Collections.EMPTY_LIST;
526
527                     int k = SAME_FRAME_EXTENDED - tag;
528                     // copy locals from prev frame and chop last k
529
locals = new ArrayList JavaDoc(frame.locals.subList(0,
530                             frame.locals.size() - k));
531
532                 } else if (tag == SAME_FRAME_EXTENDED) {
533                     frameType = SAME_FRAME_EXTENDED;
534                     stack = Collections.EMPTY_LIST;
535                     locals = new ArrayList JavaDoc(frame.locals);
536
537                 } else if ( /* tag>=APPEND && */tag < FULL_FRAME) {
538                     frameType = APPEND_FRAME;
539                     stack = Collections.EMPTY_LIST;
540
541                     // copy locals from prev frame and append new k
542
locals = new ArrayList JavaDoc(frame.locals);
543                     for (int k = tag - SAME_FRAME_EXTENDED; k > 0; k--) {
544                         off = readType(locals,
545                                 isExtCodeSize,
546                                 cr,
547                                 off,
548                                 labels,
549                                 buf);
550                     }
551
552                 } else if (tag == FULL_FRAME) {
553                     frameType = FULL_FRAME;
554
555                     // read verification_type_info locals[number_of_locals];
556
locals = new ArrayList JavaDoc();
557                     off = readTypes(locals,
558                             isExtLocals,
559                             isExtCodeSize,
560                             cr,
561                             off,
562                             labels,
563                             buf);
564
565                     // read verification_type_info stack[number_of_stack_items];
566
stack = new ArrayList JavaDoc();
567                     off = readTypes(stack,
568                             isExtStack,
569                             isExtCodeSize,
570                             cr,
571                             off,
572                             labels,
573                             buf);
574
575                 } else {
576                     throw new RuntimeException JavaDoc("Unknown frame type " + tag
577                             + " after offset " + offset);
578
579                 }
580             }
581
582             offset += offsetDelta;
583
584             Label offsetLabel = getLabel(offset, labels);
585
586             frame = new StackMapFrame(offsetLabel, locals, stack);
587             frames.add(frame);
588             // System.err.println( tag +" " + offset +" delta:" + offsetDelta +
589
// " frameType:"+ frameType+" : "+ frame);
590

591             offset++;
592         }
593
594         return new StackMapTableAttribute(frames);
595     }
596
597     protected ByteVector write(
598         ClassWriter cw,
599         byte[] code,
600         int len,
601         int maxStack,
602         int maxLocals)
603     {
604         ByteVector bv = new ByteVector();
605         // TODO verify this value (MAX_SHORT)
606
boolean isExtCodeSize = code != null && code.length > MAX_SHORT;
607         writeSize(frames.size() - 1, bv, isExtCodeSize);
608
609         if (frames.size() < 2) {
610             return bv;
611         }
612
613         boolean isExtLocals = maxLocals > MAX_SHORT;
614         boolean isExtStack = maxStack > MAX_SHORT;
615
616         // skip the first frame
617
StackMapFrame frame = (StackMapFrame) frames.get(0);
618         List JavaDoc locals = frame.locals;
619         List JavaDoc stack = frame.stack;
620         int offset = frame.label.getOffset();
621
622         for (int i = 1; i < frames.size(); i++) {
623             frame = (StackMapFrame) frames.get(i);
624
625             List JavaDoc clocals = frame.locals;
626             List JavaDoc cstack = frame.stack;
627             int coffset = frame.label.getOffset();
628
629             int clocalsSize = clocals.size();
630             int cstackSize = cstack.size();
631
632             int localsSize = locals.size();
633             int stackSize = stack.size();
634
635             int delta = coffset - offset;
636
637             int type = FULL_FRAME;
638             int k = 0;
639             if (cstackSize == 0) {
640                 k = clocalsSize - localsSize;
641                 switch (k) {
642                     case -3:
643                     case -2:
644                     case -1:
645                         type = CHOP_FRAME; // CHOP or FULL
646
localsSize = clocalsSize; // for full_frame check
647
break;
648
649                     case 0:
650                         // SAME, SAME_EXTENDED or FULL
651
type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
652                         break;
653
654                     case 1:
655                     case 2:
656                     case 3:
657                         type = APPEND_FRAME; // APPEND or FULL
658
break;
659                 }
660             } else if (localsSize == clocalsSize && cstackSize == 1) {
661                 // SAME_LOCAL_1_STACK or FULL
662
type = delta < 63
663                         ? SAME_LOCALS_1_STACK_ITEM_FRAME
664                         : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
665             }
666
667             if (type != FULL_FRAME) {
668                 // verify if stack and locals are the same
669
for (int j = 0; j < localsSize && type != FULL_FRAME; j++) {
670                     if (!locals.get(j).equals(clocals.get(j)))
671                         type = FULL_FRAME;
672                 }
673             }
674
675             switch (type) {
676                 case SAME_FRAME:
677                     bv.putByte(delta);
678                     break;
679
680                 case SAME_LOCALS_1_STACK_ITEM_FRAME:
681                     bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
682                     writeTypeInfos(bv, cw, cstack, 0, 1);
683                     break;
684
685                 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
686                     bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED);
687                     writeSize(delta, bv, isExtCodeSize);
688                     writeTypeInfos(bv, cw, cstack, 0, 1);
689                     break;
690
691                 case SAME_FRAME_EXTENDED:
692                     bv.putByte(SAME_FRAME_EXTENDED);
693                     writeSize(delta, bv, isExtCodeSize);
694                     break;
695
696                 case CHOP_FRAME:
697                     bv.putByte(SAME_FRAME_EXTENDED + k); // negative k
698
writeSize(delta, bv, isExtCodeSize);
699                     break;
700
701                 case APPEND_FRAME:
702                     bv.putByte(SAME_FRAME_EXTENDED + k); // positive k
703
writeSize(delta, bv, isExtCodeSize);
704                     writeTypeInfos(bv,
705                             cw,
706                             clocals,
707                             clocalsSize - 1,
708                             clocalsSize);
709                     break;
710
711                 case FULL_FRAME:
712                     bv.putByte(FULL_FRAME);
713                     writeSize(delta, bv, isExtCodeSize);
714                     writeSize(clocalsSize, bv, isExtLocals);
715                     writeTypeInfos(bv, cw, clocals, 0, clocalsSize);
716                     writeSize(cstackSize, bv, isExtStack);
717                     writeTypeInfos(bv, cw, cstack, 0, cstackSize);
718                     break;
719
720                 default:
721                     throw new RuntimeException JavaDoc();
722             }
723             offset = coffset + 1; // compensating non first offset
724
locals = clocals;
725             stack = cstack;
726         }
727         return bv;
728     }
729
730     private void writeSize(int delta, ByteVector bv, boolean isExt) {
731         if (isExt) {
732             bv.putInt(delta);
733         } else {
734             bv.putShort(delta);
735         }
736     }
737
738     private void writeTypeInfos(
739         ByteVector bv,
740         ClassWriter cw,
741         List JavaDoc info,
742         int start,
743         int end)
744     {
745         for (int j = start; j < end; j++) {
746             StackMapType typeInfo = (StackMapType) info.get(j);
747             bv.putByte(typeInfo.getType());
748
749             switch (typeInfo.getType()) {
750                 case StackMapType.ITEM_Object: //
751
bv.putShort(cw.newClass(typeInfo.getObject()));
752                     break;
753
754                 case StackMapType.ITEM_Uninitialized: //
755
bv.putShort(typeInfo.getLabel().getOffset());
756                     break;
757
758             }
759         }
760     }
761
762     public static int getMethodOff(ClassReader cr, int codeOff, char[] buf) {
763         int off = cr.header + 6;
764
765         int interfacesCount = cr.readUnsignedShort(off);
766         off += 2 + interfacesCount * 2;
767
768         int fieldsCount = cr.readUnsignedShort(off);
769         off += 2;
770         for (; fieldsCount > 0; --fieldsCount) {
771             int attrCount = cr.readUnsignedShort(off + 6); // field attributes
772
off += 8;
773             for (; attrCount > 0; --attrCount) {
774                 off += 6 + cr.readInt(off + 2);
775             }
776         }
777
778         int methodsCount = cr.readUnsignedShort(off);
779         off += 2;
780         for (; methodsCount > 0; --methodsCount) {
781             int methodOff = off;
782             int attrCount = cr.readUnsignedShort(off + 6); // method attributes
783
off += 8;
784             for (; attrCount > 0; --attrCount) {
785                 String JavaDoc attrName = cr.readUTF8(off, buf);
786                 off += 6;
787                 if (attrName.equals("Code")) {
788                     if (codeOff == off) {
789                         return methodOff;
790                     }
791                 }
792                 off += cr.readInt(off - 4);
793             }
794         }
795
796         return -1;
797     }
798
799     /**
800      * Use method signature and access flags to resolve initial locals state.
801      *
802      * @return list of <code>StackMapType</code> instances representing locals
803      * for an initial frame.
804      */

805     public static List JavaDoc calculateLocals(
806         String JavaDoc className,
807         int access,
808         String JavaDoc methodName,
809         String JavaDoc methodDesc)
810     {
811         List JavaDoc locals = new ArrayList JavaDoc();
812
813         // TODO
814
if ("<init>".equals(methodName)
815                 && !className.equals("java/lang/Object"))
816         {
817             StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_UninitializedThis);
818             typeInfo.setObject(className); // this
819
locals.add(typeInfo);
820         } else if ((access & Opcodes.ACC_STATIC) == 0) {
821             StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_Object);
822             typeInfo.setObject(className); // this
823
locals.add(typeInfo);
824         }
825
826         Type[] types = Type.getArgumentTypes(methodDesc);
827         for (int i = 0; i < types.length; i++) {
828             Type t = types[i];
829             StackMapType smt;
830             switch (t.getSort()) {
831                 case Type.LONG:
832                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long);
833                     break;
834                 case Type.DOUBLE:
835                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Double);
836                     break;
837
838                 case Type.FLOAT:
839                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float);
840                     break;
841
842                 case Type.ARRAY:
843                 case Type.OBJECT:
844                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Object);
845                     smt.setObject(t.getDescriptor()); // TODO verify name
846
break;
847
848                 default:
849                     smt = StackMapType.getTypeInfo(StackMapType.ITEM_Integer);
850                     break;
851             }
852         }
853
854         return locals;
855     }
856
857     private int readTypes(
858         List JavaDoc info,
859         boolean isExt,
860         boolean isExtCodeSize,
861         ClassReader cr,
862         int off,
863         Label[] labels,
864         char[] buf)
865     {
866         int n = 0;
867         if (isExt) {
868             n = cr.readInt(off);
869             off += 4;
870         } else {
871             n = cr.readUnsignedShort(off);
872             off += 2;
873         }
874
875         for (; n > 0; n--) {
876             off = readType(info, isExtCodeSize, cr, off, labels, buf);
877         }
878         return off;
879     }
880
881     private int readType(
882         List JavaDoc info,
883         boolean isExtCodeSize,
884         ClassReader cr,
885         int off,
886         Label[] labels,
887         char[] buf)
888     {
889         int itemType = cr.readByte(off++);
890         StackMapType typeInfo = StackMapType.getTypeInfo(itemType);
891         info.add(typeInfo);
892         switch (itemType) {
893             // case StackMapType.ITEM_Long: //
894
// case StackMapType.ITEM_Double: //
895
// info.add(StackMapType.getTypeInfo(StackMapType.ITEM_Top));
896
// break;
897

898             case StackMapType.ITEM_Object: //
899
typeInfo.setObject(cr.readClass(off, buf));
900                 off += 2;
901                 break;
902
903             case StackMapType.ITEM_Uninitialized: //
904
int offset;
905                 if (isExtCodeSize) {
906                     offset = cr.readInt(off);
907                     off += 4;
908                 } else {
909                     offset = cr.readUnsignedShort(off);
910                     off += 2;
911                 }
912
913                 typeInfo.setLabel(getLabel(offset, labels));
914                 break;
915         }
916         return off;
917     }
918
919     private Label getLabel(int offset, Label[] labels) {
920         Label l = labels[offset];
921         if (l != null) {
922             return l;
923         }
924         return labels[offset] = new Label();
925     }
926
927     public String JavaDoc toString() {
928         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("StackMapTable[");
929         for (int i = 0; i < frames.size(); i++) {
930             sb.append('\n').append('[').append(frames.get(i)).append(']');
931         }
932         sb.append("\n]");
933         return sb.toString();
934     }
935 }
936
Popular Tags