[jboss-svn-commits] JBL Code SVN: r31202 - in labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium: emma/rt and 1 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Mon Jan 25 10:17:30 EST 2010
Author: adinn
Date: 2010-01-25 10:17:30 -0500 (Mon, 25 Jan 2010)
New Revision: 31202
Added:
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariableTableAttribute_info.java
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariable_info.java
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMapTableAttribute_info.java
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMap_info.java
Modified:
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/instr/InstrVisitor.java
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/rt/InstrClassLoader.java
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/Attribute_info.java
labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/IAttributeVisitor.java
Log:
patched version of emma-2.0.5312 including Matt Lavin's lcoal variable table fixes and Andrew Dinn's stack map table fixes
Modified: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/instr/InstrVisitor.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/instr/InstrVisitor.java 2010-01-25 15:10:09 UTC (rev 31201)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/instr/InstrVisitor.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -1120,8 +1120,8 @@
final EmitCtx emitctx = new EmitCtx (blocks, newcode);
// create a jump adjustment map:
- final int [] jumpAdjOffsets = new int [blockCount]; // room for initial 0 + (blockCount - 1)
- final int [] jumpAdjMap = new int [jumpAdjOffsets.length]; // room for initial 0 + (blockCount - 1)
+ final int [] jumpAdjOffsets = new int [blockCount + 1]; // room for initial 0 + blockCount
+ final int [] jumpAdjMap = new int [jumpAdjOffsets.length]; // room for initial 0 + blockCount
if ($assert.ENABLED) $assert.ASSERT (jumpAdjOffsets.length == jumpAdjMap.length,
"jumpAdjOffsets and jumpAdjMap length mismatch");
@@ -1140,7 +1140,7 @@
{
jumpAdjOffsets [l + 1] = _blocks [l].m_first + _blocks [l].m_length; // implies the insertion goes just before the branch
}
-
+
block.emit (emitctx, code);
// TODO: this breaks if code can shrink:
@@ -1149,7 +1149,15 @@
jumpAdjMap [l + 1] = emitctx.m_out.size () - _blocks [l + 1].m_first;
}
}
+
+ // add an extra entry mapping positions off the end of the bytecode array to positions off the end of the new array
+ int oldBytecodeEnd = attribute.getCodeSize();
+ int newBytecodeEnd = emitctx.m_out.size ();
+
+ jumpAdjOffsets[blockCount] = oldBytecodeEnd;
+ jumpAdjMap[blockCount] = newBytecodeEnd - oldBytecodeEnd;
+
m_methodJumpAdjOffsets = jumpAdjOffsets;
m_methodJumpAdjValues = jumpAdjMap;
@@ -1345,9 +1353,92 @@
return ctx;
}
- // TODO: line var table as well
-
+ public Object visit(LocalVariableTableAttribute_info attribute, Object ctx) {
+ final boolean trace2 = m_log.atTRACE2 ();
+ if (trace2) m_log.trace2 ("visit", "attribute: [" + attribute.getName (m_cls) + "]");
+ final int lineCount = attribute.size ();
+ for (int l = 0; l < lineCount; ++ l)
+ {
+ final LocalVariable_info var = attribute.get (l);
+
+ // TODO: make this faster using either table assist or the sorted array in 'sortedLines'
+
+ // adjust bytecode offset for line number mapping:
+ int end_pc = var.m_start_pc+var.m_length; // use m_start_pc before adjustment to get original end
+
+ int adjSegment;
+
+ if (var.m_start_pc != 0) {
+ adjSegment = lowbound (m_methodJumpAdjOffsets, var.m_start_pc);
+ var.m_start_pc += m_methodJumpAdjValues [adjSegment];
+ }
+
+ adjSegment = lowbound (m_methodJumpAdjOffsets, end_pc);
+ end_pc += m_methodJumpAdjValues [adjSegment];
+ var.m_length = end_pc - var.m_start_pc;
+ }
+
+ return null;
+ }
+
+ public Object visit(StackMapTableAttribute_info attribute, Object ctx) {
+ final boolean trace2 = m_log.atTRACE2 ();
+ if (trace2) m_log.trace2 ("visit", "attribute: [" + attribute.getName (m_cls) + "]");
+
+ final int frameCount = attribute.size();
+ // first delta is exact position, the rest are diff to next offset - 1
+ // so we start with oldpos and last newpos set to -1 and always add delta + 1
+ int oldPosition = -1;
+ int lastNewPosition = -1;
+ int newPosition;
+ for (int l = 0; l < frameCount; ++ l)
+ {
+ final StackMap_info frame = attribute.get (l);
+
+ // compute the old position for the next frame
+
+ oldPosition += frame.getOffsetDelta() + 1;
+
+ // map this to the new position
+ // n.b. we add 1 to the original position before looking up the adjustment
+ // then subtract 1 from the mapped position after adjustment. this ensures
+ // that position which correspond to insert points include the inserted code.
+ // this avoids a problem where the original code contains frames located at
+ // two successive control flow instructions such as athrow followed by goto.
+ // these get replaced by <inst_seq> athrow <inst_seq> goto and if we let
+ // the markers attach before <inst_seq> successive offsets after the second
+ // one would address the wrong instruction.
+
+ int adjSegment = lowbound (m_methodJumpAdjOffsets, oldPosition);
+ int adjustment = m_methodJumpAdjValues [adjSegment];
+ newPosition = oldPosition + adjustment;
+
+ // reset to the new delta
+ int newDelta = newPosition - lastNewPosition - 1;
+ frame.resetOffsetDelta(newDelta);
+
+ lastNewPosition = newPosition;
+
+ int entryCount = frame.getEntryCount();
+
+ for (int i = 0; i < entryCount; i++) {
+ int offset = frame.getEntryOffset(i);
+ if (offset > 0) {
+ // compute old position for offset instruction
+ int oldOffsetPosition = oldPosition - offset;
+ // map this to the new offset location in the modified code
+ adjSegment = lowbound (m_methodJumpAdjOffsets, oldOffsetPosition);
+ adjustment = m_methodJumpAdjValues [adjSegment];
+ // compute the offset from the new offset location to new frame position and update
+ int newOffset = newPosition - (oldOffsetPosition + adjustment);
+ frame.setEntryOffset(i, newOffset);
+ }
+ }
+ }
+
+ return null;
+ }
// no-op visits:
public Object visit (final ExceptionsAttribute_info attribute, final Object ctx)
Modified: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/rt/InstrClassLoader.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/rt/InstrClassLoader.java 2010-01-25 15:10:09 UTC (rev 31201)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/emma/rt/InstrClassLoader.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -15,6 +15,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.security.CodeSigner;
import java.security.CodeSource;
import java.util.Map;
@@ -343,7 +344,7 @@
// support ProtectionDomains with non-null class source URLs:
// [however, disable anything related to sealing or signing]
- final CodeSource csrc = new CodeSource (srcURL, null);
+ final CodeSource csrc = new CodeSource (srcURL, (CodeSigner[])null);
// allow getPackage() to return non-null on the class we are about to
// define (however, don't bother emulating the original manifest info since
Modified: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/Attribute_info.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/Attribute_info.java 2010-01-25 15:10:09 UTC (rev 31201)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/Attribute_info.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -59,6 +59,10 @@
public static final String ATTRIBUTE_BRIDGE = "Bridge";
public static final String ATTRIBUTE_SOURCEFILE = "SourceFile";
public static final String ATTRIBUTE_INNERCLASSES = "InnerClasses";
+ public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
+ public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
+ public static final String ATTRIBUTE_STACK_MAP = "StackMap";
+ public static final String ATTRIBUTE_STACK_MAP_TABLE = "StackMapTable";
/**
* Constant pool index for {@link com.vladium.jcd.cls.constant.CONSTANT_Utf8_info}
@@ -144,6 +148,22 @@
{
return new SourceFileAttribute_info (attribute_name_index, attribute_length, bytes);
}
+ else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals (name))
+ {
+ return new LocalVariableTableAttribute_info (attribute_name_index, attribute_length, bytes);
+ }
+ else if (ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals (name))
+ {
+ return new LocalVariableTableAttribute_info (attribute_name_index, attribute_length, bytes);
+ }
+ else if (ATTRIBUTE_STACK_MAP.equals (name))
+ {
+ return new StackMapTableAttribute_info (attribute_name_index, attribute_length, bytes);
+ }
+ else if (ATTRIBUTE_STACK_MAP_TABLE.equals (name))
+ {
+ return new StackMapTableAttribute_info (attribute_name_index, attribute_length, bytes);
+ }
else
{
// default:
Modified: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/IAttributeVisitor.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/IAttributeVisitor.java 2010-01-25 15:10:09 UTC (rev 31201)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/IAttributeVisitor.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -27,6 +27,8 @@
Object visit (SyntheticAttribute_info attribute, Object ctx);
Object visit (BridgeAttribute_info attribute, Object ctx);
Object visit (InnerClassesAttribute_info attribute, Object ctx);
+ Object visit (LocalVariableTableAttribute_info attribute, Object ctx);
+ Object visit (StackMapTableAttribute_info attribute, Object ctx);
} // end of interface
// ----------------------------------------------------------------------------
Added: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariableTableAttribute_info.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariableTableAttribute_info.java (rev 0)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariableTableAttribute_info.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -0,0 +1,109 @@
+/* Copyright (C) 2007 Matt Lavin. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Common Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * $Id$
+ */
+package com.vladium.jcd.cls.attribute;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.vladium.jcd.lib.UDataInputStream;
+import com.vladium.jcd.lib.UDataOutputStream;
+
+public class LocalVariableTableAttribute_info extends Attribute_info {
+
+ private List m_variables;
+
+ public LocalVariableTableAttribute_info(int attribute_name_index, long attribute_length, UDataInputStream bytes) throws IOException {
+ super(attribute_name_index, attribute_length);
+
+ int variable_count = bytes.readU2();
+
+ m_variables = new ArrayList(variable_count);
+
+ for (int i = 0; i < variable_count; i++)
+ {
+ m_variables.add (new LocalVariable_info (bytes));
+ }
+ }
+
+ /**
+ * Returns {@link LocalVariable_info} descriptor at a given offset.
+ *
+ * @param offset line number entry offset [must be in [0, size()) range;
+ * input not checked]
+ * @return LocalVariable_info descriptor [never null]
+ *
+ * @throws IndexOutOfBoundsException if 'offset' is outside of valid range
+ */
+ public LocalVariable_info get (final int offset)
+ {
+ return (LocalVariable_info) m_variables.get (offset);
+ }
+
+ /**
+ * Returns the number of descriptors in this collection [can be 0].
+ */
+ public int size ()
+ {
+ return m_variables.size ();
+ }
+
+ public long length()
+ {
+ return 8 + (size () * 10);
+ }
+
+ // Visitor:
+
+ public void accept(IAttributeVisitor visitor, Object ctx)
+ {
+ visitor.visit (this, ctx);
+ }
+
+ // IClassFormatOutput:
+
+ public void writeInClassFormat (final UDataOutputStream out) throws IOException
+ {
+ super.writeInClassFormat (out);
+
+ final int lines_count = size ();
+ out.writeU2 (lines_count);
+
+ for (int l = 0; l < lines_count; ++ l)
+ {
+ get(l).writeInClassFormat (out);
+ }
+ }
+
+ // Cloneable:
+
+ /**
+ * Performs a deep copy.
+ */
+ public Object clone ()
+ {
+ final LocalVariableTableAttribute_info _clone = (LocalVariableTableAttribute_info) super.clone ();
+
+ // do deep copy:
+ final int lines_count = size (); // use size() if class becomes non-final
+ _clone.m_variables = new ArrayList (lines_count);
+ for (int e = 0; e < lines_count; ++ e)
+ {
+ _clone.m_variables.add (get(e).clone ());
+ }
+
+ return _clone;
+ }
+
+ public String toString()
+ {
+ return "LocalVariableTableAttribute_info: [attribute_name_index = " + m_name_index + ", attribute_length = " + m_attribute_length + ']';
+ }
+
+}
Added: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariable_info.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariable_info.java (rev 0)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/LocalVariable_info.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -0,0 +1,79 @@
+/* Copyright (C) 2007 Matt Lavin. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Common Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * $Id$
+ */
+package com.vladium.jcd.cls.attribute;
+
+import java.io.IOException;
+
+import com.vladium.jcd.compiler.IClassFormatOutput;
+import com.vladium.jcd.lib.UDataInputStream;
+import com.vladium.jcd.lib.UDataOutputStream;
+
+// ----------------------------------------------------------------------------
+
+public
+final class LocalVariable_info implements Cloneable, IClassFormatOutput
+{
+ // public: ................................................................
+
+ public int m_start_pc;
+ public int m_length;
+ public int m_name_index;
+ public int m_descriptor_index;
+ public int m_index;
+
+
+ public LocalVariable_info (final UDataInputStream bytes) throws IOException
+ {
+ m_start_pc = bytes.readU2();
+ m_length = bytes.readU2();
+ m_name_index = bytes.readU2();
+ m_descriptor_index = bytes.readU2();
+ m_index = bytes.readU2();
+ }
+
+ public String toString ()
+ {
+ return "LocalVariable_info: [start_pc = " + m_start_pc + ", length = " + m_length + "]";
+ }
+
+ // Cloneable:
+
+ /**
+ * Performs a deep copy.
+ */
+ public Object clone ()
+ {
+ try
+ {
+ return super.clone ();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new InternalError (e.toString ());
+ }
+ }
+
+ // IClassFormatOutput:
+
+ public void writeInClassFormat (final UDataOutputStream out) throws IOException
+ {
+ out.writeU2 (m_start_pc);
+ out.writeU2 (m_length);
+ out.writeU2 (m_name_index);
+ out.writeU2 (m_descriptor_index);
+ out.writeU2 (m_index);
+ }
+
+ // protected: .............................................................
+
+ // package: ...............................................................
+
+ // private: ...............................................................
+
+} // end of class
Added: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMapTableAttribute_info.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMapTableAttribute_info.java (rev 0)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMapTableAttribute_info.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -0,0 +1,168 @@
+/* Copyright (C) 2010 Andrew Dinn. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Common Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * $Id$
+ */
+package com.vladium.jcd.cls.attribute;
+
+import com.vladium.jcd.lib.UDataInputStream;
+import com.vladium.jcd.lib.UDataOutputStream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * The StackMapTable attribute is an optional variable-length attribute in
+ * the attributes table of a {@link CodeAttribute_info} attribute.<P>
+ *
+ * The StackMapTable attribute has the following format:
+ * <PRE>
+ * StackMapTable_attribute {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u2 frame_count;
+ * FrameEntry frame_table[frame_count];
+ * }
+ * <PRE>
+ * A FrameEntry details a stack layout at a particular offset in the
+ * code. The FrameEntry has several compressed formats, enabling various
+ * simple frame formats to be encoded using less space than the standard
+ * FULL frame format. A single tag byte is used to identify the frame
+ * type.
+ *
+ * Frame offsets are stored as a delta from the preceding frame's position,
+ * or from the start of the bytecode in the case of the first frame,
+ * allowing them to represented using 2 bytes (unsigned). In two cases,
+ * where the offset delta is < 63, it may be encoded in the tag byte.
+ *
+ * FULL frames provide type information for values located in the local
+ * variable data area and on the Java stack. In compressed formats this
+ * type information may be provided as differences from the previous frame
+ * or may be omitted, depending upon the format.
+ *
+ * The FrameEntry types are, SAME, SAME_ONE
+ * @author Andrew Dinn, (C) 2010
+ */
+public class StackMapTableAttribute_info extends Attribute_info {
+
+ private List m_frames;
+
+ public StackMapTableAttribute_info(int attribute_name_index, long attribute_length, UDataInputStream bytes) throws IOException {
+ super(attribute_name_index, attribute_length);
+
+ int frame_count = bytes.readU2();
+
+ m_frames = new ArrayList(frame_count);
+
+ if (DEBUG) {
+ System.out.println(" StackMapTable: read length " + (attribute_length + 6));
+ System.out.println(" StackMapTable: number_of_entries = " + frame_count);
+ }
+
+ for (int i = 0; i < frame_count; i++)
+ {
+ m_frames.add (new StackMap_info (bytes));
+ }
+ }
+
+ /**
+ * Returns {@link com.vladium.jcd.cls.attribute.LocalVariable_info} descriptor at a given offset.
+ *
+ * @param offset line number entry offset [must be in [0, size()) range;
+ * input not checked]
+ * @return LocalVariable_info descriptor [never null]
+ *
+ * @throws IndexOutOfBoundsException if 'offset' is outside of valid range
+ */
+ public StackMap_info get (final int offset)
+ {
+ return (StackMap_info) m_frames.get (offset);
+ }
+
+ /**
+ * Returns the number of descriptors in this collection [can be 0].
+ */
+ public int size ()
+ {
+ return m_frames.size ();
+ }
+
+ public long length()
+ {
+ // standard header plus 2 byte frame count
+ int length = 8;
+
+ // we need to recompute the remaining length because an adjustment to a frame offset may require a different
+ // encoding for the frame
+
+ Iterator iterator = m_frames.iterator();
+
+ while (iterator.hasNext()) {
+ StackMap_info frame = (StackMap_info) iterator.next();
+ length += frame.length();
+ }
+
+ m_attribute_length = length + 6;
+ return length;
+ }
+
+ // Visitor:
+
+ public void accept(IAttributeVisitor visitor, Object ctx)
+ {
+ visitor.visit (this, ctx);
+ }
+
+ // IClassFormatOutput:
+
+ public void writeInClassFormat (final UDataOutputStream out) throws IOException
+ {
+ super.writeInClassFormat (out);
+
+ final int frames_count = size ();
+
+ if (DEBUG) {
+ System.out.println(" StackMapTable: write length " + length());
+ System.out.println(" StackMapTable: number_of_entries = " + frames_count);
+ }
+
+ out.writeU2 (frames_count);
+
+ for (int l = 0; l < frames_count; ++ l)
+ {
+ get(l).writeInClassFormat (out);
+ }
+ }
+
+ // Cloneable:
+
+ /**
+ * Performs a deep copy.
+ */
+ public Object clone ()
+ {
+ final StackMapTableAttribute_info _clone = (StackMapTableAttribute_info) super.clone ();
+
+ // do deep copy:
+ final int frames_count = size (); // use size() if class becomes non-final
+ _clone.m_frames = new ArrayList (frames_count);
+ for (int e = 0; e < frames_count; ++ e)
+ {
+ _clone.m_frames.add (get(e).clone ());
+ }
+
+ return _clone;
+ }
+
+ public String toString()
+ {
+ return "LocalVariableTableAttribute_info: [attribute_name_index = " + m_name_index + ", attribute_length = " + m_attribute_length + ']';
+ }
+
+ private final static boolean DEBUG = false;
+}
Added: labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMap_info.java
===================================================================
--- labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMap_info.java (rev 0)
+++ labs/jbosstm/workspace/emma-2.0.5312/core/java12/com/vladium/jcd/cls/attribute/StackMap_info.java 2010-01-25 15:17:30 UTC (rev 31202)
@@ -0,0 +1,676 @@
+/* Copyright (C) 2010 Andrew Dinn. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Common Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * $Id$
+ */
+package com.vladium.jcd.cls.attribute;
+
+import com.vladium.jcd.compiler.IClassFormatOutput;
+import com.vladium.jcd.lib.UDataInputStream;
+import com.vladium.jcd.lib.UDataOutputStream;
+
+import java.io.IOException;
+
+// ----------------------------------------------------------------------------
+
+public
+final class StackMap_info implements Cloneable, IClassFormatOutput
+{
+ // public: ................................................................
+
+ public StackMap_info(final UDataInputStream bytes) throws IOException
+ {
+ m_type = bytes.readByte() & 0xFF;
+ if (DEBUG) {
+ System.out.println(" frame_type = " + m_type + " /* " + frameTypeString() + "*/");
+ }
+ // content varies depending upon which range type falls into
+ if (m_type < FRAME_SAME_ONE_STACK) {
+ readSame(bytes);
+ } else if (m_type < FRAME_RESERVED) {
+ readSameOneStack(bytes);
+ } else if (m_type < FRAME_SAME_ONE_STACK_EXTENDED) {
+ throw new RuntimeException("encountered reserved stack map frame m_type " + m_type);
+ } else if (m_type < FRAME_CHOP) {
+ readSameOneStackExtended(bytes);
+ } else if (m_type < FRAME_SAME_EXTENDED) {
+ readChop(bytes);
+ } else if (m_type < FRAME_APPEND) {
+ readSameExtended(bytes);
+ } else if (m_type < FRAME_FULL) {
+ readSameAppend(bytes);
+ } else {
+ readFull(bytes);
+ }
+ }
+
+ public String toString ()
+ {
+ return "LocalVariable_info: [type = " + m_type + ", delta = " + m_offset_delta + ", local = " + m_local + ", stack = " + m_stack + "]";
+ }
+
+ // Cloneable:
+
+ /**
+ * Performs a deep copy.
+ */
+ public Object clone ()
+ {
+ try
+ {
+ final StackMap_info _clone = (StackMap_info)super.clone ();
+ if (m_local_count > 0) {
+ _clone.m_local = new StackEntry_info[m_local_count];
+ for (int i = 0; i < m_local_count; i++) {
+ _clone.m_local[i] = (StackEntry_info)m_local[i].clone();
+ }
+ }
+ if (m_stack_count > 0) {
+ _clone.m_stack = new StackEntry_info[m_stack_count];
+ for (int i = 0; i < m_stack_count; i++) {
+ _clone.m_stack[i] = (StackEntry_info)m_stack[i].clone();
+ }
+ }
+ return _clone;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new InternalError (e.toString ());
+ }
+ }
+
+ // IClassFormatOutput:
+
+ public void writeInClassFormat (final UDataOutputStream out) throws IOException
+ {
+ if (DEBUG) {
+ System.out.println(" frame_type = " + m_type + " /* " + frameTypeString() + "*/");
+ }
+
+ out.writeByte ((byte)m_type);
+ // content varies depending upon which range type falls into
+ if (m_type < FRAME_SAME_ONE_STACK) {
+ // do nothing
+ } else if (m_type < FRAME_RESERVED) {
+ writeSameOneStack(out);
+ } else if (m_type < FRAME_CHOP) {
+ writeSameOneStackExtended(out);
+ } else if (m_type < FRAME_SAME_EXTENDED) {
+ writeChop(out);
+ } else if (m_type < FRAME_APPEND) {
+ writeSameExtended(out);
+ } else if (m_type < FRAME_FULL) {
+ writeSameAppend(out);
+ } else {
+ writeFull(out);
+ }
+ }
+
+ /**
+ * this computes the number of bytes occupied by the frame. we need this because adjusting the offset of
+ * the frame may require recoding it with a different format causing the written attribute length to differ
+ * from the read attribute length.
+ * @return the number of bytes occupied by the frame
+ */
+
+ public int length()
+ {
+ if (m_type < FRAME_SAME_ONE_STACK) {
+ // same has offset in m_type
+ return 1;
+ } else if (m_type < FRAME_RESERVED) {
+ // same_one_stack has offset in m_type plus one stack entry
+ return 1 + m_stack[0].length();
+ } else {
+ // the others have m_type and separate offset
+ int length = 3;
+
+ // only full frame inserts stack counts
+ if (m_type == FRAME_FULL) {
+ length += 4;
+ }
+ // now add space for each stack entry
+
+ // note this doesn't count anything when m_type is CHOP or SAME_EXTENDED
+ // as the count is negative or zero, respectively
+ for (int i = 0; i < m_local_count; i++) {
+ length += m_local[i].length();
+ }
+ for (int i = 0; i < m_stack_count; i++) {
+ length += m_stack[i].length();
+ }
+ return length;
+ }
+ }
+
+ /**
+ * this is called once by the visitor to increment a frame position by the relevant delta as it walks through
+ * the frames in the stack map
+ *
+ * @return the
+ */
+ public int getOffsetDelta()
+ {
+ return m_offset_delta;
+ }
+
+ /**
+ * this is called once by the visitor to remap the frame offset delta
+ */
+ public void resetOffsetDelta(int delta)
+ {
+ // ok, for the encoding which use offsets < 64 we need to update the type as well as the offset
+ // also if the offset is now too big (>= 64) we will need to re-encode the table
+ // in other cases if the offset goes above 16 bits we are stuffed anyway
+
+ if (m_type < FRAME_RESERVED) {
+
+ m_offset_delta = delta;
+
+ if (delta < 64) {
+ // ok, just update m_type to use the new offset
+ if (m_type < FRAME_SAME_ONE_STACK) {
+ // type and delta are the same
+ m_type = delta;
+ } else {
+ m_type = delta + FRAME_SAME_ONE_STACK;
+ }
+ } else {
+ // ok, so we need to use a different encoding
+ if (m_type < FRAME_SAME_ONE_STACK) {
+ // we can just recode as SAME ==> SAME_EXTENDED and use the new delta
+ m_type = FRAME_SAME_EXTENDED;
+ } else {
+ // we can just recode as FRAME_SAME_ONE_STACK ==> FRAME_SAME_ONE_STACK_EXTENDED and use the new delta
+ m_type = FRAME_SAME_ONE_STACK_EXTENDED;
+ m_offset_delta = delta;
+ }
+ }
+ } else {
+ // just update the delta
+ // TODO -- worry about what to do if this offset is now greater than 16 bits worth
+ m_offset_delta = delta;
+ }
+ }
+
+ /**
+ * compute the total number of local and stack entries in this frame
+ *
+ * @return the total number of local and stack entries
+ */
+ public int getEntryCount()
+ {
+ // local may be negative if this is a chop frame
+ int real_local_count = 0;
+ if (m_local_count > 0) {
+ real_local_count += m_local_count;
+ }
+
+ return real_local_count + m_stack_count;
+ }
+
+ /**
+ * retrieve the bytecode offset associated with an entry in this frames list of local and stack entries
+ * or -1 if the entry has no associated offset. only ENTRY_UNINIT entries have an associated offset
+ *
+ * @return the bytecode offset associated with the entry
+ */
+ public int getEntryOffset(int entryIdx)
+ {
+ StackEntry_info entry = getEntry(entryIdx);
+
+ if (entry.m_type == ENTRY_UNINIT) {
+ return entry.cpool_index_or_offset;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * update the bytecode offset associated with an entry in this frames list of local and stack entries.
+ * only ENTRY_UNINIT entries have an associated offset
+ */
+ public void setEntryOffset(int entryIdx, int offset)
+ {
+ StackEntry_info entry = getEntry(entryIdx);
+
+ // TODO -- worry about what to do if this offset is now greater than 16 bits worth
+
+ entry.cpool_index_or_offset = offset;
+ }
+
+ // protected: .............................................................
+
+ // package: ...............................................................
+
+ // private: ...............................................................
+
+ // type tags fall into ranges whose lower end is defined by these symbols
+ // SAME = 00nnnnnn nnnnnn = offset
+ // SAME_ONE_STACK = 01nnnnnn nnnnnn = offset
+ // RESERVED = 11000000 .. 11110110
+ // SAME_ONE_STACK_EXTENDED = 11110111
+ // CHOP = 111110nn nn < 3, chop count = 11 - nn
+ // SAME_EXTENDED = 11111011
+ // APPEND = 111111nn nn < 3, append count = nn + 1
+ // FULL = 11111111
+ private final static int FRAME_SAME = 0;
+ private final static int FRAME_SAME_ONE_STACK = 64;
+ private final static int FRAME_RESERVED = 128;
+ private final static int FRAME_SAME_ONE_STACK_EXTENDED = 247;
+ private final static int FRAME_CHOP = 248;
+ private final static int FRAME_SAME_EXTENDED = 251;
+ private final static int FRAME_APPEND = 252;
+ private final static int FRAME_FULL = 255;
+
+ // entries are tagged to identify what value they hold
+ private final static int ENTRY_TOP = 0; // i.e. java.lang.Object -- but no need for cpool entry
+ private final static int ENTRY_INT = 1;
+ private final static int ENTRY_FLOAT = 2;
+ private final static int ENTRY_DOUBLE = 3;
+ private final static int ENTRY_LONG = 4;
+ private final static int ENTRY_NULL = 5;
+ private final static int ENTRY_UNINIT_THIS = 6; // i.e. before calling constructor
+ private final static int ENTRY_OBJECT = 7; // also stores cpool ref for type
+ private final static int ENTRY_UNINIT = 8; // also stores offset of instruction which creates object
+
+ private int m_type;
+ private int m_offset_delta;
+ private int m_local_count;
+ private int m_stack_count;
+ private StackEntry_info[] m_local;
+ private StackEntry_info[] m_stack;
+
+
+ private void readSame(final UDataInputStream bytes)
+ {
+ // offset delta is type
+ m_offset_delta = m_type;
+ m_local_count = m_stack_count = 0;
+ m_local = null;
+ m_stack = null;
+ }
+
+ private void readSameOneStack(final UDataInputStream bytes) throws IOException
+ {
+ // offset delta is type - base of SAME_ONE_LOCAL type range;
+ m_offset_delta = m_type - FRAME_SAME_ONE_STACK;
+ m_local_count = 0;
+ m_stack_count = 1;
+ m_local = null;
+ m_stack = new StackEntry_info[1];
+ if (DEBUG) {
+ System.out.print(" stack = [ ");
+ }
+ readEntries(m_stack, m_stack_count, bytes);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void readSameOneStackExtended(final UDataInputStream bytes) throws IOException
+ {
+ // offset delta is stored in bytecode
+ m_offset_delta = bytes.readU2();
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ m_local_count = 0;
+ m_stack_count = 1;
+ m_local = null;
+ m_stack = new StackEntry_info[1];
+ if (DEBUG) {
+ System.out.print(" stack = [ ");
+ }
+ readEntries(m_stack, m_stack_count, bytes);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void readChop(final UDataInputStream bytes) throws IOException
+ {
+ // offset delta is stored in bytecode
+ m_offset_delta = bytes.readU2();
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ // number of locals removed is m_type - FRAME_CHOP but we compute this negated
+ // because m_local == null and using a negative count means for loops do no iteration
+ m_local_count = FRAME_CHOP - m_type;
+ m_stack_count = 0;
+ m_local = null;
+ m_stack = null;
+ }
+
+ private void readSameExtended(final UDataInputStream bytes) throws IOException
+ {
+ // offset delta is stored in bytecode
+ m_offset_delta = bytes.readU2();
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ // no change to locals and stack is zero
+ m_local_count = m_stack_count = 0;
+ m_local = null;
+ m_stack = null;
+ }
+
+ private void readSameAppend(final UDataInputStream bytes) throws IOException
+ {
+ // offset delta is stored in bytecode
+ m_offset_delta = bytes.readU2();
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ // number of locals added is 1 + (m_type - FRAME_APPEND)
+ // or, equivalently, m_type - FRAME_SAME_EXTENDED
+ m_local_count = m_type - FRAME_SAME_EXTENDED;
+ m_stack_count = 0;
+ m_local = new StackEntry_info[m_local_count];
+ m_stack = null;
+ if (DEBUG) {
+ System.out.print(" locals = [ ");
+ }
+ readEntries(m_local, m_local_count, bytes);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void readFull(final UDataInputStream bytes) throws IOException
+ {
+ // offset delta is stored in bytecode
+ m_offset_delta = bytes.readU2();
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ m_local_count = bytes.readU2();
+ if (DEBUG) {
+ System.out.print(" locals = [ ");
+ }
+ if (m_local_count > 0) {
+ m_local = new StackEntry_info[m_local_count];
+ readEntries(m_local, m_local_count, bytes);
+ }
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ m_stack_count = bytes.readU2();
+ if (DEBUG) {
+ System.out.print(" stack = [ ");
+ }
+ if (m_stack_count > 0) {
+ m_stack = new StackEntry_info[m_stack_count];
+ readEntries(m_stack, m_stack_count, bytes);
+ }
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void readEntries(final StackEntry_info[] entries, final int count, final UDataInputStream bytes)
+ throws IOException
+ {
+ for (int i = 0; i < count; i++) {
+ entries[i] = readEntry(bytes);
+ if (DEBUG) {
+ if (i + 1 < count) {
+ System.out.print(", ");
+ }
+ }
+ }
+ }
+
+ private StackEntry_info readEntry(final UDataInputStream bytes)
+ throws IOException
+ {
+ StackEntry_info entry = new StackEntry_info();
+ entry.m_type = bytes.readByte() & 0xFF;
+ switch (entry.m_type)
+ {
+ case ENTRY_TOP:
+ case ENTRY_INT:
+ case ENTRY_FLOAT:
+ case ENTRY_LONG:
+ case ENTRY_DOUBLE:
+ case ENTRY_NULL:
+ case ENTRY_UNINIT_THIS:
+ break;
+ case ENTRY_OBJECT:
+ entry.cpool_index_or_offset = bytes.readU2();
+ break;
+ case ENTRY_UNINIT:
+ entry.cpool_index_or_offset = bytes.readU2();
+ break;
+ }
+
+ if (DEBUG) {
+ System.out.print(entry.entryTypeString());
+ }
+ return entry;
+ }
+
+ private void writeSameOneStack(final UDataOutputStream out) throws IOException
+ {
+ // write out the one stack entry
+ if (DEBUG) {
+ System.out.print(" stack = [ ");
+ }
+ writeEntriesNoCount(m_stack, m_stack_count, out);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void writeSameOneStackExtended(final UDataOutputStream out) throws IOException
+ {
+ // write out the offset delta
+ out.writeU2(m_offset_delta);
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ // write out the one stack entry
+ if (DEBUG) {
+ System.out.print(" stack = [ ");
+ }
+ writeEntriesNoCount(m_stack, m_stack_count, out);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void writeChop(final UDataOutputStream out) throws IOException
+ {
+ // write out the offset delta
+ out.writeU2(m_offset_delta);
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ }
+
+ private void writeSameExtended(final UDataOutputStream out) throws IOException
+ {
+ // write out the offset delta
+ out.writeU2(m_offset_delta);
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ }
+
+ private void writeSameAppend(final UDataOutputStream out) throws IOException
+ {
+ // write out the offset delta and the local entries
+ out.writeU2(m_offset_delta);
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ if (DEBUG) {
+ System.out.print(" locals = [ ");
+ }
+ writeEntriesNoCount(m_local, m_local_count, out);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void writeFull(final UDataOutputStream out) throws IOException
+ {
+ // write out the offset delta, the local entries and the stack entries
+ out.writeU2(m_offset_delta);
+ if (DEBUG) {
+ System.out.println(" offset_delta = " + m_offset_delta);
+ }
+ if (DEBUG) {
+ System.out.print(" locals = [ ");
+ }
+ writeEntriesWithCount(m_local, m_local_count, out);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ if (DEBUG) {
+ System.out.print(" stack = [ ");
+ }
+ writeEntriesWithCount(m_stack, m_stack_count, out);
+ if (DEBUG) {
+ System.out.print("]\n");
+ }
+ }
+
+ private void writeEntriesWithCount(final StackEntry_info[] entries, final int count, final UDataOutputStream out)
+ throws IOException
+ {
+ out.writeU2(count);
+ writeEntriesNoCount(entries, count, out);
+ }
+
+ private void writeEntriesNoCount(final StackEntry_info[] entries, final int count, final UDataOutputStream out)
+ throws IOException
+ {
+ for (int i = 0; i < count; i++) {
+ writeEntry(entries[i], out);
+ if (DEBUG) {
+ if (i + 1 < count) {
+ System.out.print(", ");
+ }
+ }
+ }
+ }
+
+ private void writeEntry(final StackEntry_info entry, final UDataOutputStream out)
+ throws IOException
+ {
+ out.writeByte((byte)entry.m_type);
+ switch (entry.m_type)
+ {
+ case ENTRY_TOP:
+ case ENTRY_INT:
+ case ENTRY_FLOAT:
+ case ENTRY_LONG:
+ case ENTRY_DOUBLE:
+ case ENTRY_NULL:
+ case ENTRY_UNINIT_THIS:
+ break;
+ case ENTRY_OBJECT:
+ out.writeU2(entry.cpool_index_or_offset);
+ break;
+ case ENTRY_UNINIT:
+ out.writeU2(entry.cpool_index_or_offset);
+ break;
+ }
+ if (DEBUG) {
+ System.out.print(entry.entryTypeString());
+ }
+ }
+
+ private StackEntry_info getEntry(int entryIdx)
+ {
+ // we may have a negative count in the case of a CHOP frame
+ int real_local_count = 0;
+ if (m_local_count > 0) {
+ real_local_count += m_local_count;
+ }
+ if (entryIdx < real_local_count) {
+ return m_local[entryIdx];
+ } else {
+ return m_stack[entryIdx - real_local_count];
+ }
+ }
+
+ private static class StackEntry_info implements Cloneable
+ {
+ int m_type;
+ int cpool_index_or_offset;
+
+ int length()
+ {
+ if (m_type == ENTRY_OBJECT || m_type == ENTRY_UNINIT) {
+ return 3;
+ }
+
+ return 1;
+ }
+ public Object clone()
+ {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError (e.toString ());
+ }
+ }
+
+ // debug methods
+ public String entryTypeString()
+ {
+ switch(m_type) {
+ case ENTRY_TOP:
+ return "top";
+ case ENTRY_INT:
+ return "int";
+ case ENTRY_FLOAT:
+ return "float";
+ case ENTRY_LONG:
+ return "long";
+ case ENTRY_DOUBLE:
+ return "double";
+ case ENTRY_NULL:
+ return "null";
+ case ENTRY_UNINIT_THIS:
+ return "uninitialized_this";
+ case ENTRY_OBJECT:
+ {
+ return "class:" + cpool_index_or_offset;
+ }
+ default:
+ return "uninitialized:" + cpool_index_or_offset;
+ }
+ }
+ }
+ // debug only routines
+ private static final boolean DEBUG = false;
+
+ private String frameTypeString()
+ {
+ if (m_type < FRAME_SAME_ONE_STACK) {
+ return "same";
+ } else if (m_type < FRAME_RESERVED) {
+ return "same_locals_1_stack_item";
+ } else if (m_type < FRAME_SAME_ONE_STACK_EXTENDED) {
+ return "reserved";
+ } else if (m_type < FRAME_CHOP) {
+ return "same_locals_1_stack_item_extended";
+ } else if (m_type < FRAME_SAME_EXTENDED) {
+ return "chop";
+ } else if (m_type < FRAME_APPEND) {
+ return "same_extended";
+ } else if (m_type < FRAME_FULL) {
+ return "append";
+ } else {
+ return "full";
+ }
+ }
+
+} // end of class
More information about the jboss-svn-commits
mailing list