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.HashSet;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Set;
036:
037: import org.drools.asm.Attribute;
038: import org.drools.asm.ByteVector;
039: import org.drools.asm.ClassReader;
040: import org.drools.asm.ClassWriter;
041: import org.drools.asm.Label;
042:
043: /**
044: * StackMapAttribute is used by CDLC preverifier. Definition is given in
045: * appendix "CLDC Byte Code Typechecker Specification" from CDLC 1.1
046: * specification. <p> <i>Note that this implementation does not calculate
047: * StackMapFrame structures from the method bytecode. If method code is changed
048: * or generated from scratch, then developer is responsible to prepare a correct
049: * StackMapFrame structures.</i> <p> The format of the stack map in the class
050: * file is given below. In the following, <ul> <li>if the length of the
051: * method's byte code1 is 65535 or less, then <tt>uoffset</tt> represents the
052: * type u2; otherwise <tt>uoffset</tt> represents the type u4.</li> <li>If
053: * the maximum number of local variables for the method is 65535 or less, then
054: * <tt>ulocalvar</tt> represents the type u2; otherwise <tt>ulocalvar</tt>
055: * represents the type u4.</li> <li>If the maximum size of the operand stack
056: * is 65535 or less, then <tt>ustack</tt> represents the type u2; otherwise
057: * ustack represents the type u4.</li> </ul>
058: *
059: * <pre>
060: * stack_map { // attribute StackMap
061: * u2 attribute_name_index;
062: * u4 attribute_length
063: * uoffset number_of_entries;
064: * stack_map_frame entries[number_of_entries];
065: * }
066: * </pre>
067: *
068: * Each stack map frame has the following format:
069: *
070: * <pre>
071: * stack_map_frame {
072: * uoffset offset;
073: * ulocalvar number_of_locals;
074: * verification_type_info locals[number_of_locals];
075: * ustack number_of_stack_items;
076: * verification_type_info stack[number_of_stack_items];
077: * }
078: * </pre>
079: *
080: * The <tt>verification_type_info</tt> structure consists of a one-byte tag
081: * followed by zero or more bytes, giving more information about the tag. Each
082: * <tt>verification_type_info</tt> structure specifies the verification type
083: * of one or two locations.
084: *
085: * <pre>
086: * union verification_type_info {
087: * Top_variable_info;
088: * Integer_variable_info;
089: * Float_variable_info;
090: * Long_variable_info;
091: * Double_variable_info;
092: * Null_variable_info;
093: * UninitializedThis_variable_info;
094: * Object_variable_info;
095: * Uninitialized_variable_info;
096: * }
097: *
098: * Top_variable_info {
099: * u1 tag = ITEM_Top; // 0
100: * }
101: *
102: * Integer_variable_info {
103: * u1 tag = ITEM_Integer; // 1
104: * }
105: *
106: * Float_variable_info {
107: * u1 tag = ITEM_Float; // 2
108: * }
109: *
110: * Long_variable_info {
111: * u1 tag = ITEM_Long; // 4
112: * }
113: *
114: * Double_variable_info {
115: * u1 tag = ITEM_Double; // 3
116: * }
117: *
118: * Null_variable_info {
119: * u1 tag = ITEM_Null; // 5
120: * }
121: *
122: * UninitializedThis_variable_info {
123: * u1 tag = ITEM_UninitializedThis; // 6
124: * }
125: *
126: * Object_variable_info {
127: * u1 tag = ITEM_Object; // 7
128: * u2 cpool_index;
129: * }
130: *
131: * Uninitialized_variable_info {
132: * u1 tag = ITEM_Uninitialized // 8
133: * uoffset offset;
134: * }
135: * </pre>
136: *
137: * @see <a href="http://www.jcp.org/en/jsr/detail?id=139">JSR 139 : Connected
138: * Limited Device Configuration 1.1</a>
139: *
140: * @author Eugene Kuleshov
141: */
142: public class StackMapAttribute extends Attribute {
143:
144: static final int MAX_SIZE = 65535;
145:
146: /**
147: * A List of <code>StackMapFrame</code> instances.
148: */
149: public List frames = new ArrayList();
150:
151: public StackMapAttribute() {
152: super ("StackMap");
153: }
154:
155: public StackMapAttribute(final List frames) {
156: this ();
157: this .frames = frames;
158: }
159:
160: public List getFrames() {
161: return this .frames;
162: }
163:
164: public StackMapFrame getFrame(final Label label) {
165: for (int i = 0; i < this .frames.size(); i++) {
166: final StackMapFrame frame = (StackMapFrame) this .frames
167: .get(i);
168: if (frame.label == label) {
169: return frame;
170: }
171: }
172: return null;
173: }
174:
175: public boolean isUnknown() {
176: return false;
177: }
178:
179: public boolean isCodeAttribute() {
180: return true;
181: }
182:
183: protected Attribute read(final ClassReader cr, int off,
184: final int len, final char[] buf, final int codeOff,
185: final Label[] labels) {
186: final StackMapAttribute attr = new StackMapAttribute();
187: // note that this is not the size of Code attribute
188: final boolean isExtCodeSize = cr.readInt(codeOff + 4) > StackMapAttribute.MAX_SIZE;
189: final boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > StackMapAttribute.MAX_SIZE;
190: final boolean isExtStack = cr.readUnsignedShort(codeOff) > StackMapAttribute.MAX_SIZE;
191:
192: int size = 0;
193: if (isExtCodeSize) {
194: size = cr.readInt(off);
195: off += 4;
196: } else {
197: size = cr.readUnsignedShort(off);
198: off += 2;
199: }
200: for (int i = 0; i < size; i++) {
201: int offset;
202: if (isExtCodeSize) {
203: offset = cr.readInt(off);
204: off += 4;
205: } else {
206: offset = cr.readUnsignedShort(off);
207: off += 2;
208: }
209:
210: final Label label = getLabel(offset, labels);
211: final List locals = new ArrayList();
212: final List stack = new ArrayList();
213:
214: off = readTypeInfo(cr, off, locals, labels, buf,
215: isExtLocals, isExtCodeSize);
216: off = readTypeInfo(cr, off, stack, labels, buf, isExtStack,
217: isExtCodeSize);
218:
219: attr.frames.add(new StackMapFrame(label, locals, stack));
220: }
221: return attr;
222: }
223:
224: private int readTypeInfo(final ClassReader cr, int off,
225: final List info, final Label[] labels, final char[] buf,
226: final boolean isExt, final boolean isExtCode) {
227: int n = 0;
228: if (isExt) {
229: n = cr.readInt(off);
230: off += 4;
231: } else {
232: n = cr.readUnsignedShort(off);
233: off += 2;
234: }
235: for (int j = 0; j < n; j++) {
236: final int itemType = cr.readByte(off++);
237: final StackMapType typeInfo = StackMapType
238: .getTypeInfo(itemType);
239: info.add(typeInfo);
240: switch (itemType) {
241: case StackMapType.ITEM_Object: //
242: typeInfo.setObject(cr.readClass(off, buf));
243: off += 2;
244: break;
245: case StackMapType.ITEM_Uninitialized: //
246: int offset;
247: if (isExtCode) {
248: offset = cr.readInt(off);
249: off += 4;
250: } else {
251: offset = cr.readUnsignedShort(off);
252: off += 2;
253: }
254: typeInfo.setLabel(getLabel(offset, labels));
255: break;
256: }
257: }
258: return off;
259: }
260:
261: private void writeTypeInfo(final ByteVector bv,
262: final ClassWriter cw, final List info, final int max) {
263: if (max > StackMapAttribute.MAX_SIZE) {
264: bv.putInt(info.size());
265: } else {
266: bv.putShort(info.size());
267: }
268: for (int j = 0; j < info.size(); j++) {
269: final StackMapType typeInfo = (StackMapType) info.get(j);
270: bv.putByte(typeInfo.getType());
271: switch (typeInfo.getType()) {
272: case StackMapType.ITEM_Object: //
273: bv.putShort(cw.newClass(typeInfo.getObject()));
274: break;
275:
276: case StackMapType.ITEM_Uninitialized: //
277: bv.putShort(typeInfo.getLabel().getOffset());
278: break;
279:
280: }
281: }
282: }
283:
284: private Label getLabel(final int offset, final Label[] labels) {
285: final Label l = labels[offset];
286: if (l != null) {
287: return l;
288: }
289: return labels[offset] = new Label();
290: }
291:
292: protected ByteVector write(final ClassWriter cw, final byte[] code,
293: final int len, final int maxStack, final int maxLocals) {
294: final ByteVector bv = new ByteVector();
295: if (code != null && code.length > StackMapAttribute.MAX_SIZE) { // TODO verify value
296: bv.putInt(this .frames.size());
297: } else {
298: bv.putShort(this .frames.size());
299: }
300: for (int i = 0; i < this .frames.size(); i++) {
301: writeFrame((StackMapFrame) this .frames.get(i), cw,
302: maxStack, maxLocals, bv);
303: }
304: return bv;
305: }
306:
307: protected Label[] getLabels() {
308: final HashSet labels = new HashSet();
309: for (int i = 0; i < this .frames.size(); i++) {
310: getFrameLabels((StackMapFrame) this .frames.get(i), labels);
311: }
312: return (Label[]) labels.toArray(new Label[labels.size()]);
313: }
314:
315: private void writeFrame(final StackMapFrame frame,
316: final ClassWriter cw, final int maxStack,
317: final int maxLocals, final ByteVector bv) {
318: bv.putShort(frame.label.getOffset());
319: writeTypeInfo(bv, cw, frame.locals, maxLocals);
320: writeTypeInfo(bv, cw, frame.stack, maxStack);
321: }
322:
323: private void getFrameLabels(final StackMapFrame frame,
324: final Set labels) {
325: labels.add(frame.label);
326: getTypeInfoLabels(labels, frame.locals);
327: getTypeInfoLabels(labels, frame.stack);
328: }
329:
330: private void getTypeInfoLabels(final Set labels, final List info) {
331: for (final Iterator it = info.iterator(); it.hasNext();) {
332: final StackMapType typeInfo = (StackMapType) it.next();
333: if (typeInfo.getType() == StackMapType.ITEM_Uninitialized) {
334: labels.add(typeInfo.getLabel());
335: }
336: }
337: }
338:
339: public String toString() {
340: final StringBuffer sb = new StringBuffer("StackMap[");
341: for (int i = 0; i < this .frames.size(); i++) {
342: sb.append('\n').append('[').append(this .frames.get(i))
343: .append(']');
344: }
345: sb.append("\n]");
346: return sb.toString();
347: }
348: }
|