diff options
Diffstat (limited to 'src/fjbg/ch/epfl/lamp/fjbg/JStackMapTableAttribute.java')
-rw-r--r-- | src/fjbg/ch/epfl/lamp/fjbg/JStackMapTableAttribute.java | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JStackMapTableAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JStackMapTableAttribute.java new file mode 100644 index 0000000000..da7f00bf3e --- /dev/null +++ b/src/fjbg/ch/epfl/lamp/fjbg/JStackMapTableAttribute.java @@ -0,0 +1,282 @@ +/* FJBG -- Fast Java Bytecode Generator + * Copyright 2002-2011 LAMP/EPFL + * @author Michel Schinz + */ + +package ch.epfl.lamp.fjbg; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * + * @author Stephane Micheloud + * @version 1.0 + */ + +public class JStackMapTableAttribute extends JAttribute { + /** Constant pool of the current classfile. */ + private JConstantPool pool; + + /** StackMapTable entries */ + protected final List/*<Frame>*/ entries = new ArrayList(); + protected int entriesSize = 0; + protected boolean usesU2; + + public JStackMapTableAttribute(FJBGContext context, + JClass clazz, + JCode code) { + super(context, clazz); + this.pool = clazz.pool; + + assert code.getOwner().getOwner() == clazz; + } + + public JStackMapTableAttribute(FJBGContext context, + JClass clazz, + Object owner, + String name, + int size, + DataInputStream stream) + throws IOException { + super(context, clazz, name); + this.pool = clazz.pool; + + int count = stream.readShort(); + this.usesU2 = count < 65536; + for (int i = 0; i < count; ++i) + this.entries.add(new Frame(stream)); + this.entriesSize = computeSize(); + + assert name.equals(getName()); + } + + public String getName() { return "StackMapTable"; } + + // Follows javap output format for StackMapTable attribute. + /*@Override*/ public String toString() { + Frame frame = null; + StringBuffer buf = new StringBuffer(" StackMapTable: number_of_entries = "); + buf.append(entries.size()); + Iterator it = entries.iterator(); + while (it.hasNext()) { + frame = (Frame)it.next(); + buf.append("\n frame_type = "); + buf.append(frame.tag); + buf.append(" /* "); + buf.append(getFrameType(frame.tag)); + buf.append(" */"); + if (frame.offsetDelta != -1) + buf.append("\n offset_delta = "+frame.offsetDelta); + if (frame.locals != null) + appendTypeInfoArray(buf, "locals", frame.locals); + if (frame.stackItems != null) + appendTypeInfoArray(buf, "stack", frame.stackItems); + } + buf.append("\n"); + return buf.toString(); + } + + protected int getSize() { + return entriesSize; + } + + protected void writeContentsTo(DataOutputStream stream) throws IOException { + stream.writeShort(entriesSize); + Iterator it = entries.iterator(); + while (it.hasNext()) { + Frame frame = (Frame)it.next(); + frame.writeContentsTo(stream); + } + } + + private class TypeInfo { + final int tag; + final int poolIndexOrOffset; // tag == 7 => poolIndex, tag = 8 => offset + private int bytes; + TypeInfo(DataInputStream stream) throws IOException { + int size = 1; + this.tag = stream.readByte(); + if (tag == 7) { // ITEM_Object; // 7 + poolIndexOrOffset = stream.readShort(); + size += 2; + } else if (tag == 8) { // ITEM_Uninitialized // 8 + poolIndexOrOffset = (usesU2) ? stream.readShort() : stream.readInt(); + size += (usesU2) ? 2 : 4; + } else + poolIndexOrOffset = -1; + this.bytes += size; + } + int getSize() { return bytes; } + void writeContentsTo(DataOutputStream stream) throws IOException { + stream.writeByte(tag); + if (tag == 7) { // ITEM_Object; // 7 + stream.writeShort(poolIndexOrOffset); + } else if (tag == 8) { // ITEM_Uninitialized // 8 + if (usesU2) stream.writeShort(poolIndexOrOffset); + else stream.writeInt(poolIndexOrOffset); + } + } + /*@Override*/ public String toString() { + switch (tag) { + case 0: // ITEM_Top + return "<top>"; + case 1: // ITEM_Integer + return "int"; + case 2: // ITEM_Float + return "float"; + case 3: // ITEM_Double + return "double"; + case 4: // ITEM_Long + return "long"; + case 5: // ITEM_Null + return "null"; + case 6: // ITEM_UninializedThis + return "this"; + case 7: // ITEM_Object + String name = pool.lookupClass(poolIndexOrOffset); + if (name.startsWith("[")) name = "\""+name+"\""; + return "class "+name; + case 8: // ITEM_Uninitialized + return "<uninitialized>"; + default: + return ""+tag; + } + } + } + + private class Frame { + final int tag; + int offsetDelta = -1; + TypeInfo[] stackItems = null; + TypeInfo[] locals = null; + private int bytes; + Frame(DataInputStream stream) throws IOException { + // The stack_map_frame structure consists of a one-byte tag + // followed by zero or more bytes. + this.tag = stream.readUnsignedByte(); + if (tag < 64) { // SAME; // 0-63 + //done + } else if (tag < 128) { // SAME_LOCALS_1_STACK_ITEM; // 64-127 + this.offsetDelta = tag - 64; + readStackItems(stream, 1); + } else if (tag < 248) { // reserved for future use. + assert false : "Tags in the range [128-247] are reserved for future use."; + } else if (tag < 251) { // CHOP; // 248-250 + int k = 251 - tag; + readOffsetDelta(stream); + } else if (tag == 251) { // SAME_FRAME_EXTENDED + readOffsetDelta(stream); + } else if (tag < 255) { // APPEND; // 252-254 + readOffsetDelta(stream); + readLocals(stream, tag - 251); + } else { // FULL_FRAME; // 255 + readOffsetDelta(stream); + readLocals(stream); + readStackItems(stream); + } + } + int getSize() { return bytes; } + void readOffsetDelta(DataInputStream stream) throws IOException { + this.offsetDelta = (usesU2) ? stream.readShort() : stream.readInt(); + this.bytes += (usesU2) ? 2 : 4; + } + int getOffsetDelta() { return offsetDelta; } + void readStackItems(DataInputStream stream, int k) throws IOException { + this.stackItems = new TypeInfo[k]; + for (int i = 0; i < k; ++i) { + stackItems[i] = new TypeInfo(stream); + this.bytes += stackItems[i].getSize(); + } + } + void readStackItems(DataInputStream stream) throws IOException { + int k = (usesU2) ? stream.readShort() : stream.readInt(); + this.bytes += (usesU2) ? 2 : 4; + readStackItems(stream, k); + } + void readLocals(DataInputStream stream, int k) throws IOException { + this.locals = new TypeInfo[k]; + for (int i = 0; i < k; ++i) { + locals[i] = new TypeInfo(stream); + this.bytes += locals[i].getSize(); + } + } + void readLocals(DataInputStream stream) throws IOException { + int k = (usesU2) ? stream.readShort() : stream.readInt(); + this.bytes += (usesU2) ? 2 : 4; + readLocals(stream, k); + } + void writeContentsTo(DataOutputStream stream) throws IOException { + stream.writeByte(tag); + if (tag < 64) { + //done + } else if (tag < 128) { // SAME; // 0-63 + assert stackItems.length == 1; + stackItems[0].writeContentsTo(stream); + } else if (tag < 248) { + assert false : "Tags in the range [128-247] are reserved for future use."; + } else if (tag < 251) { + if (usesU2) stream.writeShort(offsetDelta); + else stream.writeInt(offsetDelta); + } else if (tag == 251) { + if (usesU2) stream.writeShort(offsetDelta); + else stream.writeInt(offsetDelta); + } else if (tag < 255) { // APPEND; // 252-254 + if (usesU2) stream.writeShort(offsetDelta); + else stream.writeInt(offsetDelta); + for (int i = 0; i < locals.length; ++i) + locals[i].writeContentsTo(stream); + } else { + if (usesU2) stream.writeShort(offsetDelta); + else stream.writeInt(offsetDelta); + for (int i = 0; i < locals.length; ++i) + locals[i].writeContentsTo(stream); + for (int i = 0; i < stackItems.length; ++i) + stackItems[i].writeContentsTo(stream); + } + } + } + + private int computeSize() { + int size = (usesU2) ? 2 : 4; // number of frames + Iterator it = entries.iterator(); + while (it.hasNext()) { + Frame frame = (Frame)it.next(); + size += frame.getSize(); + } + return size; + } + + private static final String getFrameType(int tag) { + if (tag < 64) return "same"; + else if (tag < 128) return "same locals 1 stack item"; + else if (tag < 248) return "<reserved>"; + else if (tag < 251) return "chop"; + else if (tag == 251) return "same frame extended"; + else if (tag < 255) return "append"; + else return "full frame"; + } + + private static StringBuffer appendTypeInfoArray(StringBuffer buf, + String s, TypeInfo[] a) { + buf.append("\n "); + buf.append(s); + buf.append(" = "); + if (a.length > 0) { + buf.append("[ "); + for (int i = 0; i < a.length; ++i) { + if (i > 0) buf.append(", "); + buf.append(a[i]); + } + buf.append(" ]"); + } + else + buf.append("[]"); + return buf; + } + +} |