001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.bytecode;
017:
018: import java.io.DataInputStream;
019: import java.io.DataOutputStream;
020: import java.io.ByteArrayOutputStream;
021: import java.io.IOException;
022: import java.util.Map;
023:
024: /**
025: * <code>stack_map</code> attribute.
026: *
027: * <p>This is an entry in the attributes table of a Code attribute.
028: * It was introduced by J2SE 6 for the process of verification by
029: * typechecking.
030: *
031: * @since 3.4
032: */
033: public class StackMapTable extends AttributeInfo {
034: /**
035: * The name of this attribute <code>"StackMapTable"</code>.
036: */
037: public static final String tag = "StackMapTable";
038:
039: /**
040: * Constructs a <code>stack_map</code> attribute.
041: */
042: private StackMapTable(ConstPool cp, byte[] newInfo) {
043: super (cp, tag, newInfo);
044: }
045:
046: StackMapTable(ConstPool cp, int name_id, DataInputStream in)
047: throws IOException {
048: super (cp, name_id, in);
049: }
050:
051: /**
052: * Makes a copy.
053: */
054: public AttributeInfo copy(ConstPool newCp, Map classnames) {
055: int s = info.length;
056: byte[] newInfo = new byte[s];
057: System.arraycopy(info, 0, newInfo, 0, s);
058: return new StackMapTable(newCp, newInfo);
059: }
060:
061: void write(DataOutputStream out) throws IOException {
062: super .write(out);
063: }
064:
065: /**
066: * <code>Top_variable_info.tag</code>.
067: */
068: public static final int TOP = 0;
069:
070: /**
071: * <code>Float_variable_info.tag</code>.
072: */
073: public static final int INTEGER = 1;
074:
075: /**
076: * <code>Integer_variable_info.tag</code>.
077: */
078: public static final int FLOAT = 2;
079:
080: /**
081: * <code>Double_variable_info.tag</code>.
082: */
083: public static final int DOUBLE = 3;
084:
085: /**
086: * <code>Long_variable_info.tag</code>.
087: */
088: public static final int LONG = 4;
089:
090: /**
091: * <code>Null_variable_info.tag</code>.
092: */
093: public static final int NULL = 5;
094:
095: /**
096: * <code>UninitializedThis_variable_info.tag</code>.
097: */
098: public static final int THIS = 6;
099:
100: /**
101: * <code>Object_variable_info.tag</code>.
102: */
103: public static final int OBJECT = 7;
104:
105: /**
106: * <code>Uninitialized_variable_info.tag</code>.
107: */
108: public static final int UNINIT = 8;
109:
110: /**
111: * A code walker for a StackMapTable attribute.
112: */
113: static class Walker {
114: byte[] info;
115: int numOfEntries;
116:
117: /**
118: * Constructs a walker.
119: *
120: * @param data the <code>info</code> field of the
121: * <code>attribute_info</code> structure.
122: */
123: public Walker(byte[] data) {
124: info = data;
125: numOfEntries = ByteArray.readU16bit(data, 0);
126: }
127:
128: /**
129: * Returns the number of the entries.
130: */
131: public final int size() {
132: return numOfEntries;
133: }
134:
135: /**
136: * Visits each entry of the stack map frames.
137: */
138: public final void parse() throws BadBytecode {
139: int n = numOfEntries;
140: int pos = 2;
141: for (int i = 0; i < n; i++)
142: pos = stackMapFrames(pos, i);
143: }
144:
145: /**
146: * Invoked when the next entry of the stack map frames is visited.
147: *
148: * @param pos the position of the frame in the <code>info</code>
149: * field of <code>attribute_info</code> structure.
150: * @param nth the frame is the N-th
151: * (0, 1st, 2nd, 3rd, 4th, ...) entry.
152: * @return the position of the next frame.
153: */
154: int stackMapFrames(int pos, int nth) throws BadBytecode {
155: int type = info[pos] & 0xff;
156: if (type < 64) {
157: sameFrame(pos, type);
158: pos++;
159: } else if (type < 128)
160: pos = sameLocals(pos, type);
161: else if (type < 247)
162: throw new BadBytecode("bad frame_type in StackMapTable");
163: else if (type == 247) // SAME_LOCALS_1_STACK_ITEM_EXTENDED
164: pos = sameLocals(pos, type);
165: else if (type < 251) {
166: int offset = ByteArray.readU16bit(info, pos + 1);
167: chopFrame(pos, offset, 251 - type);
168: pos += 3;
169: } else if (type == 251) { // SAME_FRAME_EXTENDED
170: int offset = ByteArray.readU16bit(info, pos + 1);
171: sameFrame(pos, offset);
172: pos += 3;
173: } else if (type < 255)
174: pos = appendFrame(pos, type);
175: else
176: // FULL_FRAME
177: pos = fullFrame(pos);
178:
179: return pos;
180: }
181:
182: /**
183: * Invoked if the visited frame is a <code>same_frame</code> or
184: * a <code>same_frame_extended</code>.
185: *
186: * @param pos the position of this frame in the <code>info</code>
187: * field of <code>attribute_info</code> structure.
188: * @param offsetDelta
189: */
190: public void sameFrame(int pos, int offsetDelta) {
191: }
192:
193: private int sameLocals(int pos, int type) {
194: int offset;
195: if (type < 128)
196: offset = type - 64;
197: else { // type == 247
198: offset = ByteArray.readU16bit(info, pos + 1);
199: pos += 2;
200: }
201:
202: int tag = info[pos + 1] & 0xff;
203: int data = 0;
204: if (tag == OBJECT || tag == UNINIT) {
205: data = ByteArray.readU16bit(info, pos + 2);
206: pos += 2;
207: }
208:
209: sameLocals(pos, offset, tag, data);
210: return pos + 2;
211: }
212:
213: /**
214: * Invoked if the visited frame is a <code>same_locals_1_stack_item_frame</code>
215: * or a <code>same_locals_1_stack_item_frame_extended</code>.
216: *
217: * @param pos the position.
218: * @param offsetDelta
219: * @param stackTag <code>stack[0].tag</code>.
220: * @param stackData <code>stack[0].cpool_index</code>
221: * if the tag is <code>OBJECT</code>,
222: * or <code>stack[0].offset</code>
223: * if the tag is <code>UNINIT</code>.
224: */
225: public void sameLocals(int pos, int offsetDelta, int stackTag,
226: int stackData) {
227: }
228:
229: /**
230: * Invoked if the visited frame is a <code>chop_frame</code>.
231: *
232: * @param pos the position.
233: * @param offsetDelta
234: * @param k the <cod>k</code> last locals are absent.
235: */
236: public void chopFrame(int pos, int offsetDelta, int k) {
237: }
238:
239: private int appendFrame(int pos, int type) {
240: int k = type - 251;
241: int offset = ByteArray.readU16bit(info, pos + 1);
242: int[] tags = new int[k];
243: int[] data = new int[k];
244: int p = pos + 3;
245: for (int i = 0; i < k; i++) {
246: int tag = info[p] & 0xff;
247: tags[i] = tag;
248: if (tag == OBJECT || tag == UNINIT) {
249: data[i] = ByteArray.readU16bit(info, p + 1);
250: p += 3;
251: } else {
252: data[i] = 0;
253: p++;
254: }
255: }
256:
257: appendFrame(pos, offset, tags, data);
258: return p;
259: }
260:
261: /**
262: * Invoked if the visited frame is a <code>append_frame</code>.
263: *
264: * @param pos the position.
265: * @param offsetDelta
266: * @param tags <code>locals[i].tag</code>.
267: * @param data <code>locals[i].cpool_index</code>
268: * or <cod>locals[i].offset</code>.
269: */
270: public void appendFrame(int pos, int offsetDelta, int[] tags,
271: int[] data) {
272: }
273:
274: private int fullFrame(int pos) {
275: int offset = ByteArray.readU16bit(info, pos + 1);
276: int numOfLocals = ByteArray.readU16bit(info, pos + 3);
277: int[] localsTags = new int[numOfLocals];
278: int[] localsData = new int[numOfLocals];
279: int p = verifyTypeInfo(pos + 5, numOfLocals, localsTags,
280: localsData);
281: int numOfItems = ByteArray.readU16bit(info, p);
282: int[] itemsTags = new int[numOfItems];
283: int[] itemsData = new int[numOfItems];
284: p = verifyTypeInfo(p + 2, numOfItems, itemsTags, itemsData);
285: fullFrame(pos, offset, localsTags, localsData, itemsTags,
286: itemsData);
287: return p;
288: }
289:
290: /**
291: * Invoked if the visited frame is <code>full_frame</code>.
292: *
293: * @param pos the position.
294: * @param offsetDelta
295: * @param localTags <code>locals[i].tag</code>
296: * @param localData <code>locals[i].cpool_index</code>
297: * or <code>locals[i].offset</code>
298: * @param stackTags <code>stack[i].tag</code>
299: * @param stackData <code>stack[i].cpool_index</code>
300: * or <code>stack[i].offset</code>
301: */
302: void fullFrame(int pos, int offsetDelta, int[] localTags,
303: int[] localData, int[] stackTags, int[] stackData) {
304: }
305:
306: private int verifyTypeInfo(int pos, int n, int[] tags,
307: int[] data) {
308: for (int i = 0; i < n; i++) {
309: int tag = info[pos++] & 0xff;
310: tags[i] = tag;
311: if (tag == OBJECT || tag == UNINIT) {
312: data[i] = ByteArray.readU16bit(info, pos);
313: pos += 2;
314: }
315: }
316:
317: return pos;
318: }
319: }
320:
321: /**
322: * A writer of stack map tables.
323: */
324: static class Writer {
325: ByteArrayOutputStream output;
326: int numOfEntries;
327:
328: /**
329: * Constructs a writer.
330: * @param size the initial buffer size.
331: */
332: public Writer(int size) {
333: output = new ByteArrayOutputStream(size);
334: numOfEntries = 0;
335: output.write(0); // u2 number_of_entries
336: output.write(0);
337: }
338:
339: /**
340: * Returns the stack map table written out.
341: */
342: public byte[] toByteArray() {
343: byte[] b = output.toByteArray();
344: ByteArray.write16bit(numOfEntries, b, 0);
345: return b;
346: }
347:
348: /**
349: * Writes a <code>same_frame</code> or a <code>same_frame_extended</code>.
350: */
351: public void sameFrame(int offsetDelta) {
352: numOfEntries++;
353: if (offsetDelta < 64)
354: output.write(offsetDelta);
355: else {
356: output.write(251); // SAME_FRAME_EXTENDED
357: write16(offsetDelta);
358: }
359: }
360:
361: /**
362: * Writes a <code>same_locals_1_stack_item</code>
363: * or a <code>same_locals_1_stack_item_extended</code>.
364: *
365: * @param tag <code>stack[0].tag</code>.
366: * @param data <code>stack[0].cpool_index</code>
367: * if the tag is <code>OBJECT</code>,
368: * or <cod>stack[0].offset</code>
369: * if the tag is <code>UNINIT</code>.
370: * Otherwise, this parameter is not used.
371: */
372: public void sameLocals(int offsetDelta, int tag, int data) {
373: numOfEntries++;
374: if (offsetDelta < 64)
375: output.write(offsetDelta + 64);
376: else {
377: output.write(247); // SAME_LOCALS_1_STACK_ITEM_EXTENDED
378: write16(offsetDelta);
379: }
380:
381: writeTypeInfo(tag, data);
382: }
383:
384: /**
385: * Writes a <code>chop_frame</code>.
386: *
387: * @param k the number of absent locals. 1, 2, or 3.
388: */
389: public void chopFrame(int offsetDelta, int k) {
390: numOfEntries++;
391: output.write(251 - k);
392: write16(offsetDelta);
393: }
394:
395: /**
396: * Writes a <code>append_frame</code>.
397: *
398: * @param tag <code>locals[].tag</code>.
399: * The length of this array must be
400: * either 1, 2, or 3.
401: * @param data <code>locals[].cpool_index</code>
402: * if the tag is <code>OBJECT</code>,
403: * or <cod>locals[].offset</code>
404: * if the tag is <code>UNINIT</code>.
405: * Otherwise, this parameter is not used.
406: */
407: public void appendFrame(int offsetDelta, int[] tags, int[] data) {
408: numOfEntries++;
409: int k = tags.length; // k is 1, 2, or 3
410: output.write(k + 251);
411: write16(offsetDelta);
412: for (int i = 0; i < k; i++)
413: writeTypeInfo(tags[i], data[i]);
414: }
415:
416: /**
417: * Writes a <code>full_frame</code>.
418: *
419: * @param localTags <code>locals[].tag</code>.
420: * @param localData <code>locals[].cpool_index</code>
421: * if the tag is <code>OBJECT</code>,
422: * or <cod>locals[].offset</code>
423: * if the tag is <code>UNINIT</code>.
424: * Otherwise, this parameter is not used.
425: * @param stackTags <code>stack[].tag</code>.
426: * @param stackData <code>stack[].cpool_index</code>
427: * if the tag is <code>OBJECT</code>,
428: * or <cod>stack[].offset</code>
429: * if the tag is <code>UNINIT</code>.
430: * Otherwise, this parameter is not used.
431: */
432: public void fullFrame(int offsetDelta, int[] localTags,
433: int[] localData, int[] stackTags, int[] stackData) {
434: numOfEntries++;
435: output.write(255); // FULL_FRAME
436: write16(offsetDelta);
437: int n = localTags.length;
438: write16(n);
439: for (int i = 0; i < n; i++)
440: writeTypeInfo(localTags[i], localData[i]);
441:
442: n = stackTags.length;
443: for (int i = 0; i < n; i++)
444: writeTypeInfo(stackTags[i], stackData[i]);
445: }
446:
447: private void writeTypeInfo(int tag, int data) {
448: output.write(tag);
449: if (tag == OBJECT || tag == UNINIT)
450: write16(data);
451: }
452:
453: private void write16(int value) {
454: output.write((value >>> 8) & 0xff);
455: output.write(value & 0xff);
456: }
457: }
458: }
|