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