[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