KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > 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 com.tc.asm.attrs;
31
32 import java.util.ArrayList JavaDoc;
33 import java.util.Collections JavaDoc;
34 import java.util.List JavaDoc;
35
36 import com.tc.asm.Attribute;
37 import com.tc.asm.ByteVector;
38 import com.tc.asm.ClassReader;
39 import com.tc.asm.ClassWriter;
40 import com.tc.asm.Label;
41 import com.tc.asm.Opcodes;
42 import com.tc.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             if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) { // SAME_FRAME
491
offsetDelta = tag;
492
493                 locals = new ArrayList JavaDoc(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 JavaDoc(frame.locals);
500                 stack = new ArrayList JavaDoc();
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 JavaDoc(frame.locals);
515                     stack = new ArrayList JavaDoc();
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 JavaDoc(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 JavaDoc(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 JavaDoc(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 JavaDoc();
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 JavaDoc();
558                     off = readTypes(stack,
559                             isExtStack,
560                             isExtCodeSize,
561                             cr,
562                             off,
563                             labels,
564                             buf);
565
566                 } else {
567                     throw new RuntimeException JavaDoc("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 JavaDoc 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 JavaDoc clocals = frame.locals;
616             List JavaDoc 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 JavaDoc();
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 JavaDoc 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 JavaDoc 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 JavaDoc calculateLocals(
798         String JavaDoc className,
799         int access,
800         String JavaDoc methodName,
801         String JavaDoc methodDesc)
802     {
803         List JavaDoc locals = new ArrayList JavaDoc();
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 JavaDoc 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 JavaDoc 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 JavaDoc toString() {
920         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("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
Popular Tags