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 org.drools.asm.attrs;
030:
031: import java.util.ArrayList;
032: import java.util.Collections;
033: import java.util.List;
034:
035: import org.drools.asm.Attribute;
036: import org.drools.asm.ByteVector;
037: import org.drools.asm.ClassReader;
038: import org.drools.asm.ClassWriter;
039: import org.drools.asm.Label;
040: import org.drools.asm.Opcodes;
041: import org.drools.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(final List frames) {
416: this ();
417: this .frames = frames;
418: }
419:
420: public List getFrames() {
421: return this .frames;
422: }
423:
424: public StackMapFrame getFrame(final Label label) {
425: for (int i = 0; i < this .frames.size(); i++) {
426: final StackMapFrame frame = (StackMapFrame) this .frames
427: .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(final ClassReader cr, int off,
444: final int len, final char[] buf, final int codeOff,
445: final Label[] labels) {
446:
447: final ArrayList frames = new ArrayList();
448:
449: // note that this is not the size of Code attribute
450: final boolean isExtCodeSize = cr.readInt(codeOff + 4) > StackMapTableAttribute.MAX_SHORT;
451: final boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > StackMapTableAttribute.MAX_SHORT;
452: final boolean isExtStack = cr.readUnsignedShort(codeOff) > StackMapTableAttribute.MAX_SHORT;
453:
454: int offset = 0;
455:
456: final int methodOff = getMethodOff(cr, codeOff, buf);
457: StackMapFrame frame = new StackMapFrame(
458: getLabel(offset, labels), calculateLocals(cr.readClass(
459: cr.header + 2, buf), // owner
460: cr.readUnsignedShort(methodOff), // method access
461: cr.readUTF8(methodOff + 2, buf), // method name
462: cr.readUTF8(methodOff + 4, buf)), // method desc
463: Collections.EMPTY_LIST);
464: frames.add(frame);
465:
466: // System.err.println( cr.readUTF8( methodOff + 2, buf));
467: // System.err.println( offset +" delta:" + 0 +" : "+ frame);
468:
469: int size;
470: if (isExtCodeSize) {
471: size = cr.readInt(off);
472: off += 4;
473: } else {
474: size = cr.readUnsignedShort(off);
475: off += 2;
476: }
477:
478: for (; size > 0; size--) {
479: final int tag = cr.readByte(off); // & 0xff;
480: off++;
481:
482: List stack;
483: List locals;
484:
485: int offsetDelta;
486: if (tag < StackMapTableAttribute.SAME_LOCALS_1_STACK_ITEM_FRAME) { // SAME_FRAME
487: offsetDelta = tag;
488:
489: locals = new ArrayList(frame.locals);
490: stack = Collections.EMPTY_LIST;
491:
492: } else if (tag < StackMapTableAttribute.RESERVED) { // SAME_LOCALS_1_STACK_ITEM_FRAME
493: offsetDelta = tag
494: - StackMapTableAttribute.SAME_LOCALS_1_STACK_ITEM_FRAME;
495:
496: locals = new ArrayList(frame.locals);
497: stack = new ArrayList();
498: // read verification_type_info stack[1];
499: off = readType(stack, isExtCodeSize, cr, off, labels,
500: buf);
501:
502: } else {
503: if (isExtCodeSize) {
504: offsetDelta = cr.readInt(off);
505: off += 4;
506: } else {
507: offsetDelta = cr.readUnsignedShort(off);
508: off += 2;
509: }
510:
511: if (tag == StackMapTableAttribute.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
512: locals = new ArrayList(frame.locals);
513: stack = new ArrayList();
514: // read verification_type_info stack[1];
515: off = readType(stack, isExtCodeSize, cr, off,
516: labels, buf);
517:
518: } else if (tag >= StackMapTableAttribute.CHOP_FRAME
519: && tag < StackMapTableAttribute.SAME_FRAME_EXTENDED) { // CHOP_FRAME
520: stack = Collections.EMPTY_LIST;
521:
522: final int k = StackMapTableAttribute.SAME_FRAME_EXTENDED
523: - tag;
524: // copy locals from prev frame and chop last k
525: locals = new ArrayList(frame.locals.subList(0,
526: frame.locals.size() - k));
527:
528: } else if (tag == StackMapTableAttribute.SAME_FRAME_EXTENDED) { // SAME_FRAME_EXTENDED
529: stack = Collections.EMPTY_LIST;
530: locals = new ArrayList(frame.locals);
531:
532: } else if ( /* tag>=APPEND && */tag < StackMapTableAttribute.FULL_FRAME) { // APPEND_FRAME
533: stack = Collections.EMPTY_LIST;
534:
535: // copy locals from prev frame and append new k
536: locals = new ArrayList(frame.locals);
537: for (int k = tag
538: - StackMapTableAttribute.SAME_FRAME_EXTENDED; k > 0; k--) {
539: off = readType(locals, isExtCodeSize, cr, off,
540: labels, buf);
541: }
542:
543: } else if (tag == StackMapTableAttribute.FULL_FRAME) { // FULL_FRAME
544: // read verification_type_info locals[number_of_locals];
545: locals = new ArrayList();
546: off = readTypes(locals, isExtLocals, isExtCodeSize,
547: cr, off, labels, buf);
548:
549: // read verification_type_info stack[number_of_stack_items];
550: stack = new ArrayList();
551: off = readTypes(stack, isExtStack, isExtCodeSize,
552: cr, off, labels, buf);
553:
554: } else {
555: throw new RuntimeException("Unknown frame type "
556: + tag + " after offset " + offset);
557:
558: }
559: }
560:
561: offset += offsetDelta;
562:
563: final Label offsetLabel = getLabel(offset, labels);
564:
565: frame = new StackMapFrame(offsetLabel, locals, stack);
566: frames.add(frame);
567: // System.err.println( tag +" " + offset +" delta:" + offsetDelta +
568: // " frameType:"+ frameType+" : "+ frame);
569:
570: offset++;
571: }
572:
573: return new StackMapTableAttribute(frames);
574: }
575:
576: protected ByteVector write(final ClassWriter cw, final byte[] code,
577: final int len, final int maxStack, final int maxLocals) {
578: final ByteVector bv = new ByteVector();
579: // TODO verify this value (MAX_SHORT)
580: final boolean isExtCodeSize = code != null
581: && code.length > StackMapTableAttribute.MAX_SHORT;
582: writeSize(this .frames.size() - 1, bv, isExtCodeSize);
583:
584: if (this .frames.size() < 2) {
585: return bv;
586: }
587:
588: final boolean isExtLocals = maxLocals > StackMapTableAttribute.MAX_SHORT;
589: final boolean isExtStack = maxStack > StackMapTableAttribute.MAX_SHORT;
590:
591: // skip the first frame
592: StackMapFrame frame = (StackMapFrame) this .frames.get(0);
593: List locals = frame.locals;
594: int offset = frame.label.getOffset();
595:
596: for (int i = 1; i < this .frames.size(); i++) {
597: frame = (StackMapFrame) this .frames.get(i);
598:
599: final List clocals = frame.locals;
600: final List cstack = frame.stack;
601: final int coffset = frame.label.getOffset();
602:
603: final int clocalsSize = clocals.size();
604: final int cstackSize = cstack.size();
605:
606: int localsSize = locals.size();
607:
608: final int delta = coffset - offset;
609:
610: int type = StackMapTableAttribute.FULL_FRAME;
611: int k = 0;
612: if (cstackSize == 0) {
613: k = clocalsSize - localsSize;
614: switch (k) {
615: case -3:
616: case -2:
617: case -1:
618: type = StackMapTableAttribute.CHOP_FRAME; // CHOP or FULL
619: localsSize = clocalsSize; // for full_frame check
620: break;
621:
622: case 0:
623: // SAME, SAME_EXTENDED or FULL
624: type = delta < 64 ? StackMapTableAttribute.SAME_FRAME
625: : StackMapTableAttribute.SAME_FRAME_EXTENDED;
626: break;
627:
628: case 1:
629: case 2:
630: case 3:
631: type = StackMapTableAttribute.APPEND_FRAME; // APPEND or FULL
632: break;
633: }
634: } else if (localsSize == clocalsSize && cstackSize == 1) {
635: // SAME_LOCAL_1_STACK or FULL
636: type = delta < 63 ? StackMapTableAttribute.SAME_LOCALS_1_STACK_ITEM_FRAME
637: : StackMapTableAttribute.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
638: }
639:
640: if (type != StackMapTableAttribute.FULL_FRAME) {
641: // verify if stack and locals are the same
642: for (int j = 0; j < localsSize
643: && type != StackMapTableAttribute.FULL_FRAME; j++) {
644: if (!locals.get(j).equals(clocals.get(j))) {
645: type = StackMapTableAttribute.FULL_FRAME;
646: }
647: }
648: }
649:
650: switch (type) {
651: case SAME_FRAME:
652: bv.putByte(delta);
653: break;
654:
655: case SAME_LOCALS_1_STACK_ITEM_FRAME:
656: bv
657: .putByte(StackMapTableAttribute.SAME_LOCALS_1_STACK_ITEM_FRAME
658: + delta);
659: writeTypeInfos(bv, cw, cstack, 0, 1);
660: break;
661:
662: case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
663: bv
664: .putByte(StackMapTableAttribute.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED);
665: writeSize(delta, bv, isExtCodeSize);
666: writeTypeInfos(bv, cw, cstack, 0, 1);
667: break;
668:
669: case SAME_FRAME_EXTENDED:
670: bv.putByte(StackMapTableAttribute.SAME_FRAME_EXTENDED);
671: writeSize(delta, bv, isExtCodeSize);
672: break;
673:
674: case CHOP_FRAME:
675: bv.putByte(StackMapTableAttribute.SAME_FRAME_EXTENDED
676: + k); // negative k
677: writeSize(delta, bv, isExtCodeSize);
678: break;
679:
680: case APPEND_FRAME:
681: bv.putByte(StackMapTableAttribute.SAME_FRAME_EXTENDED
682: + k); // positive k
683: writeSize(delta, bv, isExtCodeSize);
684: writeTypeInfos(bv, cw, clocals, clocalsSize - 1,
685: clocalsSize);
686: break;
687:
688: case FULL_FRAME:
689: bv.putByte(StackMapTableAttribute.FULL_FRAME);
690: writeSize(delta, bv, isExtCodeSize);
691: writeSize(clocalsSize, bv, isExtLocals);
692: writeTypeInfos(bv, cw, clocals, 0, clocalsSize);
693: writeSize(cstackSize, bv, isExtStack);
694: writeTypeInfos(bv, cw, cstack, 0, cstackSize);
695: break;
696:
697: default:
698: throw new RuntimeException();
699: }
700: offset = coffset + 1; // compensating non first offset
701: locals = clocals;
702: }
703: return bv;
704: }
705:
706: private void writeSize(final int delta, final ByteVector bv,
707: final boolean isExt) {
708: if (isExt) {
709: bv.putInt(delta);
710: } else {
711: bv.putShort(delta);
712: }
713: }
714:
715: private void writeTypeInfos(final ByteVector bv,
716: final ClassWriter cw, final List info, final int start,
717: final int end) {
718: for (int j = start; j < end; j++) {
719: final StackMapType typeInfo = (StackMapType) info.get(j);
720: bv.putByte(typeInfo.getType());
721:
722: switch (typeInfo.getType()) {
723: case StackMapType.ITEM_Object: //
724: bv.putShort(cw.newClass(typeInfo.getObject()));
725: break;
726:
727: case StackMapType.ITEM_Uninitialized: //
728: bv.putShort(typeInfo.getLabel().getOffset());
729: break;
730:
731: }
732: }
733: }
734:
735: public static int getMethodOff(final ClassReader cr,
736: final int codeOff, final char[] buf) {
737: int off = cr.header + 6;
738:
739: final int interfacesCount = cr.readUnsignedShort(off);
740: off += 2 + interfacesCount * 2;
741:
742: int fieldsCount = cr.readUnsignedShort(off);
743: off += 2;
744: for (; fieldsCount > 0; --fieldsCount) {
745: int attrCount = cr.readUnsignedShort(off + 6); // field attributes
746: off += 8;
747: for (; attrCount > 0; --attrCount) {
748: off += 6 + cr.readInt(off + 2);
749: }
750: }
751:
752: int methodsCount = cr.readUnsignedShort(off);
753: off += 2;
754: for (; methodsCount > 0; --methodsCount) {
755: final int methodOff = off;
756: int attrCount = cr.readUnsignedShort(off + 6); // method attributes
757: off += 8;
758: for (; attrCount > 0; --attrCount) {
759: final String attrName = cr.readUTF8(off, buf);
760: off += 6;
761: if (attrName.equals("Code")) {
762: if (codeOff == off) {
763: return methodOff;
764: }
765: }
766: off += cr.readInt(off - 4);
767: }
768: }
769:
770: return -1;
771: }
772:
773: /**
774: * Use method signature and access flags to resolve initial locals state.
775: *
776: * @param className name of the method's owner class.
777: * @param access access flags of the method.
778: * @param methodName name of the method.
779: * @param methodDesc descriptor of the method.
780: * @return list of <code>StackMapType</code> instances representing locals
781: * for an initial frame.
782: */
783: public static List calculateLocals(final String className,
784: final int access, final String methodName,
785: final String methodDesc) {
786: final List locals = new ArrayList();
787:
788: // TODO
789: if ("<init>".equals(methodName)
790: && !className.equals("java/lang/Object")) {
791: final StackMapType typeInfo = StackMapType
792: .getTypeInfo(StackMapType.ITEM_UninitializedThis);
793: typeInfo.setObject(className); // this
794: locals.add(typeInfo);
795: } else if ((access & Opcodes.ACC_STATIC) == 0) {
796: final StackMapType typeInfo = StackMapType
797: .getTypeInfo(StackMapType.ITEM_Object);
798: typeInfo.setObject(className); // this
799: locals.add(typeInfo);
800: }
801:
802: final Type[] types = Type.getArgumentTypes(methodDesc);
803: for (int i = 0; i < types.length; i++) {
804: final Type t = types[i];
805: StackMapType smt;
806: switch (t.getSort()) {
807: case Type.LONG:
808: smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long);
809: break;
810: case Type.DOUBLE:
811: smt = StackMapType
812: .getTypeInfo(StackMapType.ITEM_Double);
813: break;
814:
815: case Type.FLOAT:
816: smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float);
817: break;
818:
819: case Type.ARRAY:
820: case Type.OBJECT:
821: smt = StackMapType
822: .getTypeInfo(StackMapType.ITEM_Object);
823: smt.setObject(t.getDescriptor()); // TODO verify name
824: break;
825:
826: default:
827: smt = StackMapType
828: .getTypeInfo(StackMapType.ITEM_Integer);
829: break;
830: }
831: }
832:
833: return locals;
834: }
835:
836: private int readTypes(final List info, final boolean isExt,
837: final boolean isExtCodeSize, final ClassReader cr, int off,
838: final Label[] labels, final char[] buf) {
839: int n = 0;
840: if (isExt) {
841: n = cr.readInt(off);
842: off += 4;
843: } else {
844: n = cr.readUnsignedShort(off);
845: off += 2;
846: }
847:
848: for (; n > 0; n--) {
849: off = readType(info, isExtCodeSize, cr, off, labels, buf);
850: }
851: return off;
852: }
853:
854: private int readType(final List info, final boolean isExtCodeSize,
855: final ClassReader cr, int off, final Label[] labels,
856: final char[] buf) {
857: final int itemType = cr.readByte(off++);
858: final StackMapType typeInfo = StackMapType
859: .getTypeInfo(itemType);
860: info.add(typeInfo);
861: switch (itemType) {
862: // case StackMapType.ITEM_Long: //
863: // case StackMapType.ITEM_Double: //
864: // info.add(StackMapType.getTypeInfo(StackMapType.ITEM_Top));
865: // break;
866:
867: case StackMapType.ITEM_Object: //
868: typeInfo.setObject(cr.readClass(off, buf));
869: off += 2;
870: break;
871:
872: case StackMapType.ITEM_Uninitialized: //
873: int offset;
874: if (isExtCodeSize) {
875: offset = cr.readInt(off);
876: off += 4;
877: } else {
878: offset = cr.readUnsignedShort(off);
879: off += 2;
880: }
881:
882: typeInfo.setLabel(getLabel(offset, labels));
883: break;
884: }
885: return off;
886: }
887:
888: private Label getLabel(final int offset, final Label[] labels) {
889: final Label l = labels[offset];
890: if (l != null) {
891: return l;
892: }
893: return labels[offset] = new Label();
894: }
895:
896: public String toString() {
897: final StringBuffer sb = new StringBuffer("StackMapTable[");
898: for (int i = 0; i < this .frames.size(); i++) {
899: sb.append('\n').append('[').append(this .frames.get(i))
900: .append(']');
901: }
902: sb.append("\n]");
903: return sb.toString();
904: }
905: }
|