]> source.dussan.org Git - javassist.git/commitdiff
for JIRA JASSIST-95
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Sun, 8 Nov 2009 14:53:47 +0000 (14:53 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Sun, 8 Nov 2009 14:53:47 +0000 (14:53 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@502 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

src/main/javassist/CtBehavior.java
src/main/javassist/bytecode/ClassFileWriter.java
src/main/javassist/bytecode/CodeAttribute.java
src/main/javassist/bytecode/CodeIterator.java
src/main/javassist/bytecode/StackMap.java
src/main/javassist/bytecode/StackMapTable.java
src/main/javassist/bytecode/stackmap/MapMaker.java

index 7c26d0933a071a33ed460dd91ef51f29f746246c..1414d05d7ec4bf0854d0ba4e42ec39993d4aa2cb 100644 (file)
@@ -627,6 +627,10 @@ public abstract class CtBehavior extends CtMember {
             StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag);
             if (smt != null)
                 smt.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo);
+
+            StackMap sm = (StackMap)ca.getAttribute(StackMap.tag);
+            if (sm != null)
+                sm.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo);
         }
     }
 
index 2dcbfc1ccfda78b72f061839f4a502005b18599c..e1d835bd714884141b96efca9dabdfe61507a669 100644 (file)
@@ -115,7 +115,7 @@ public class ClassFileWriter {
             }
             else if (ai instanceof StackMap) {
                 out.println("<stack map begin>");
-                StackMap.Printer.print((StackMap)ai, out);
+                ((StackMap)ai).print(out);
                 out.println("<stack map end>");
             }
             else if (ai instanceof SignatureAttribute) {
index 45da15cb6430c0d47b7809ab0343c28a2684a95f..59948e2a5c7faa3d4c81f18d64cdba488ecc7399 100644 (file)
@@ -452,15 +452,16 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
     /**
      * Changes the index numbers of the local variables
      * to append a new parameter.
-     * This method does not update <code>LocalVariableAttribute</code>
-     * or <code>StackMapTable</code>.  These attributes must be
-     * explicitly updated.
+     * This method does not update <code>LocalVariableAttribute</code>,
+     * <code>StackMapTable</code>, or <code>StackMap</code>.
+     * These attributes must be explicitly updated.
      *
      * @param where         the index of the new parameter.
      * @param size         the type size of the new parameter (1 or 2).
      *
      * @see LocalVariableAttribute#shiftIndex(int, int)
      * @see StackMapTable#insertLocal(int, int, int)
+     * @see StackMap#insertLocal(int, int, int)
      */
     public void insertLocalVar(int where, int size) throws BadBytecode {
         CodeIterator ci = iterator();
index 80507fc08b92dc459e567de55996f5ae31c2bd03..14db6055939a5b11a34c7351c8c2854451691ba0 100644 (file)
@@ -843,6 +843,10 @@ public class CodeIterator implements Opcode {
         if (smt != null)
             smt.shiftPc(where, gapLength, exclusive);
 
+        StackMap sm = (StackMap)ca.getAttribute(StackMap.tag);
+        if (sm != null)
+            sm.shiftPc(where, gapLength, exclusive);
+
         return newcode;
     }
 
@@ -993,6 +997,7 @@ public class CodeIterator implements Opcode {
         LineNumberAttribute line;
         LocalVariableAttribute vars, types;
         StackMapTable stack;
+        StackMap stack2;
 
         Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca) {
             cursor = cur;
@@ -1003,6 +1008,7 @@ public class CodeIterator implements Opcode {
             vars = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.tag);
             types = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.typeTag);
             stack = (StackMapTable)ca.getAttribute(StackMapTable.tag);
+            stack2 = (StackMap)ca.getAttribute(StackMap.tag);
         }
 
         void shiftPc(int where, int gapLength, boolean exclusive) throws BadBytecode {
@@ -1027,6 +1033,9 @@ public class CodeIterator implements Opcode {
 
             if (stack != null)
                 stack.shiftPc(where, gapLength, exclusive);
+
+            if (stack2 != null)
+                stack2.shiftPc(where, gapLength, exclusive);
         }
     }
 
index 06b637ee43258d7843c4a2c47d672485fba6ab4f..ead1dffbf7e1e14bfe1ee931905a8e4e4c8ffeba 100644 (file)
@@ -20,6 +20,11 @@ import java.io.DataInputStream;
 import java.io.IOException;
 import java.util.Map;
 
+import javassist.CannotCompileException;
+import javassist.bytecode.StackMapTable.InsertLocal;
+import javassist.bytecode.StackMapTable.NewRemover;
+import javassist.bytecode.StackMapTable.Shifter;
+
 /**
  * Another <code>stack_map</code> attribute defined in CLDC 1.1 for J2ME.
  *
@@ -31,6 +36,7 @@ import java.util.Map;
  * is more than 64K.  However, for the J2ME CLDC technology, they are always 16bit.
  * The implementation of the StackMap class assumes they are 16bit.  
  *
+ * @see MethodInfo#doPreverify
  * @see StackMapTable
  * @since 3.12
  */
@@ -110,99 +116,384 @@ public class StackMap extends AttributeInfo {
      * Makes a copy.
      */
     public AttributeInfo copy(ConstPool newCp, Map classnames) {
-        ConstPool cp = getConstPool();
-        byte[] srcInfo = info;
-        byte[] newInfo = new byte[srcInfo.length];
-        int num = numOfEntries();
-        ByteArray.write16bit(num, newInfo, 0);
-        int pos = 2;
-        for (int i = 0; i < num; i++) {
-            int offset = ByteArray.readU16bit(srcInfo, pos);
-            ByteArray.write16bit(offset, newInfo, pos);
-            pos += 2;
-            int numLoc = ByteArray.readU16bit(srcInfo, pos);
-            ByteArray.write16bit(numLoc, newInfo, pos);
-            pos = copyFrames(srcInfo, newInfo, pos + 2, numLoc, cp, newCp,
-                             classnames);
-            int numStack = ByteArray.readU16bit(srcInfo, pos);
-            ByteArray.write16bit(numStack, newInfo, pos);
-            pos = copyFrames(srcInfo, newInfo, pos + 2, numStack, cp, newCp,
-                             classnames);
-        }
-
-        return new StackMap(newCp, newInfo);
-    }
-
-    private static int copyFrames(byte[] srcInfo, byte[] newInfo, int pos,
-            int numFrames, ConstPool cp, ConstPool newCp, Map classnames) {
-        for (int k = 0; k < numFrames; k++) {
-            byte tag = srcInfo[pos];
-            newInfo[pos] = tag;
+        Copier copier = new Copier(this, newCp, classnames);
+        copier.visit();
+        return copier.getStackMap();
+    }
+
+    /**
+     * A code walker for a StackMap attribute.
+     */
+    public static class Walker {
+        byte[] info;
+
+        /**
+         * Constructs a walker.
+         */
+        public Walker(StackMap sm) {
+            info = sm.get();
+        }
+
+        /**
+         * Visits each entry of the stack map frames. 
+         */
+        public void visit() {
+            int num = ByteArray.readU16bit(info, 0);
+            int pos = 2;
+            for (int i = 0; i < num; i++) {
+                int offset = ByteArray.readU16bit(info, pos);
+                int numLoc = ByteArray.readU16bit(info, pos + 2);
+                pos = locals(pos + 4, offset, numLoc);
+                int numStack = ByteArray.readU16bit(info, pos);
+                pos = stack(pos + 2, offset, numStack);
+            }
+        }
+
+        /**
+         * Invoked when <code>locals</code> of <code>stack_map_frame</code>
+         * is visited.  
+         */
+        public int locals(int pos, int offset, int num) {
+            return typeInfoArray(pos, offset, num, true);
+        }
+
+        /**
+         * Invoked when <code>stack</code> of <code>stack_map_frame</code>
+         * is visited.  
+         */
+        public int stack(int pos, int offset, int num) {
+            return typeInfoArray(pos, offset, num, false);
+        }
+
+        /**
+         * Invoked when an array of <code>verification_type_info</code> is
+         * visited.
+         *
+         * @param num       the number of elements.
+         * @param isLocals  true if this array is for <code>locals</code>.
+         *                  false if it is for <code>stack</code>.
+         * @return
+         */
+        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
+            for (int k = 0; k < num; k++)
+                pos = typeInfoArray2(k, pos);
+
+            return pos;
+        }
+
+        int typeInfoArray2(int k, int pos) {
+            byte tag = info[pos];
             if (tag == OBJECT) {
-                int clazz = ByteArray.readU16bit(srcInfo, pos + 1);
-                clazz = cp.copy(clazz, newCp, classnames);
-                ByteArray.write16bit(clazz, newInfo, pos + 1);
+                int clazz = ByteArray.readU16bit(info, pos + 1);
+                objectVariable(pos, clazz);
                 pos += 3;
             }
             else if (tag == UNINIT) {
-                ByteArray.write16bit(ByteArray.readU16bit(srcInfo, pos + 1),
-                        newInfo, pos + 1);
+                int offsetOfNew = ByteArray.readU16bit(info, pos + 1);
+                uninitialized(pos, offsetOfNew);
                 pos += 3;
             }
-            else
+            else {
+                typeInfo(pos, tag);
                 pos++;
+            }
+
+            return pos;
         }
 
-        return pos;
+        /**
+         * Invoked when an element of <code>verification_type_info</code>
+         * (except <code>Object_variable_info</code> and
+         * <code>Uninitialized_variable_info</code>) is visited.
+         */
+        public void typeInfo(int pos, byte tag) {}
+
+        /**
+         * Invoked when an element of type <code>Object_variable_info</code>
+         * is visited.
+         */
+        public void objectVariable(int pos, int clazz) {}
+
+        /**
+         * Invoked when an element of type <code>Uninitialized_variable_info</code>
+         * is visited.
+         */
+        public void uninitialized(int pos, int offset) {}
+    }
+
+    static class Copier extends Walker {
+        byte[] dest;
+        ConstPool srcCp, destCp;
+        Map classnames;
+
+        Copier(StackMap map, ConstPool newCp, Map classnames) {
+            super(map);
+            srcCp = map.getConstPool();
+            dest = new byte[info.length];
+            destCp = newCp;
+            this.classnames = classnames;
+        }
+        
+        public void visit() {
+            int num = ByteArray.readU16bit(info, 0);
+            ByteArray.write16bit(num, dest, 0);
+            super.visit();
+        }
+
+        public int locals(int pos, int offset, int num) {
+            ByteArray.write16bit(offset, dest, pos - 4);
+            return super.locals(pos, offset, num);
+        }
+
+        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
+            ByteArray.write16bit(num, dest, pos - 2);
+            return super.typeInfoArray(pos, offset, num, isLocals);
+        }
+
+        public void typeInfo(int pos, byte tag) {
+            dest[pos] = tag;
+        }
+
+        public void objectVariable(int pos, int clazz) {
+            dest[pos] = OBJECT;
+            int newClazz = srcCp.copy(clazz, destCp, classnames);
+            ByteArray.write16bit(newClazz, dest, pos + 1);
+        }
+
+        public void uninitialized(int pos, int offset) {
+            dest[pos] = UNINIT;
+            ByteArray.write16bit(offset, dest, pos + 1);
+        }
+
+        public StackMap getStackMap() {
+            return new StackMap(destCp, dest);
+        }
     }
 
     /**
-     * Printer
+     * Updates this stack map table when a new local variable is inserted
+     * for a new parameter.
+     *
+     * @param index          the index of the added local variable.
+     * @param tag            the type tag of that local variable.
+     *                       It is available by <code>StackMapTable.typeTagOf(char)</code>.
+     * @param classInfo      the index of the <code>CONSTANT_Class_info</code> structure
+     *                       in a constant pool table.  This should be zero unless the tag
+     *                       is <code>ITEM_Object</code>.
+     *
+     * @see javassist.CtBehavior#addParameter(javassist.CtClass)
+     * @see StackMapTable#typeTagOf(char)
+     * @see ConstPool
      */
-    public static class Printer {
-        /**
-         * Prints a <code>StackMap</code> attribute.
-         *
-         * @param sm        the <code>StackMap</code> attribute.
-         * @param cp        the <code>ConstPool</code> of the class file
-         *                  containing the <code>StackMap</code> attribute.
-         */
-        public static void print(StackMap sm, java.io.PrintWriter out) {
-            int num = sm.numOfEntries();
-            out.println(num + " entries");
-            byte[] srcInfo = sm.get();
-            int pos = 2;
-            for (int i = 0; i < num; i++) {
-                int offset = ByteArray.readU16bit(srcInfo, pos);
-                out.println("  * offset " + offset);
-                pos += 2;
-                int numLoc = ByteArray.readU16bit(srcInfo, pos);
-                pos = printFrames(srcInfo, pos + 2, numLoc);
-                int numStack = ByteArray.readU16bit(srcInfo, pos);
-                pos = printFrames(srcInfo, pos + 2, numStack);
+    public void insertLocal(int index, int tag, int classInfo)
+        throws BadBytecode
+    {
+        byte[] data = new InsertLocal(this, index, tag, classInfo).doit();
+        this.set(data);
+    }
+
+    static class SimpleCopy extends Walker {
+        Writer writer;
+
+        SimpleCopy(StackMap map) {
+            super(map);
+            writer = new Writer();
+        }
+
+        byte[] doit() {
+            visit();
+            return writer.toByteArray();
+        }
+
+        public void visit() {
+            int num = ByteArray.readU16bit(info, 0);
+            writer.write16bit(num);
+            super.visit();
+        }
+
+        public int locals(int pos, int offset, int num) {
+            writer.write16bit(offset);
+            return super.locals(pos, offset, num);
+        }
+
+        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
+            writer.write16bit(num);
+            return super.typeInfoArray(pos, offset, num, isLocals);
+        }
+
+        public void typeInfo(int pos, byte tag) {
+            writer.writeVerifyTypeInfo(tag, 0);
+        }
+
+        public void objectVariable(int pos, int clazz) {
+            writer.writeVerifyTypeInfo(OBJECT, clazz);
+        }
+
+        public void uninitialized(int pos, int offset) {
+            writer.writeVerifyTypeInfo(UNINIT, offset);
+        }
+    }
+
+    static class InsertLocal extends SimpleCopy {
+        private int varIndex;
+        private int varTag, varData;
+
+        InsertLocal(StackMap map, int varIndex, int varTag, int varData) {
+            super(map);
+            this.varIndex = varIndex;
+            this.varTag = varTag;
+            this.varData = varData;
+        }
+
+        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
+            if (!isLocals || num < varIndex)
+                return super.typeInfoArray(pos, offset, num, isLocals);
+
+            writer.write16bit(num + 1);
+            for (int k = 0; k < num; k++) {
+                if (k == varIndex)
+                    writeVarTypeInfo();
+
+                pos = typeInfoArray2(k, pos);
             }
+
+            if (num == varIndex)
+                writeVarTypeInfo();
+
+            return pos;
+        }
+
+        private void writeVarTypeInfo() {
+            if (varTag == OBJECT)
+                writer.writeVerifyTypeInfo(OBJECT, varData);
+            else if (varTag == UNINIT)
+                writer.writeVerifyTypeInfo(UNINIT, varData);
+            else
+                writer.writeVerifyTypeInfo(varTag, 0);
+        }
+    }
+
+    void shiftPc(int where, int gapSize, boolean exclusive)
+        throws BadBytecode
+    {
+        new Shifter(this, where, gapSize, exclusive).visit();
+    }
+
+    static class Shifter extends Walker {
+        private int where, gap;
+        private boolean exclusive;
+
+        public Shifter(StackMap smt, int where, int gap, boolean exclusive) {
+            super(smt);
+            this.where = where;
+            this.gap = gap;
+            this.exclusive = exclusive;
         }
 
-        private static int printFrames(byte[] srcInfo, int pos,
-                                       int numFrames) {
-            for (int k = 0; k < numFrames; k++) {
-                byte tag = srcInfo[pos];
+        public int locals(int pos, int offset, int num) {
+            if (exclusive ? where <= offset : where < offset)
+                ByteArray.write16bit(offset + gap, info, pos - 4);
+
+            return super.locals(pos, offset, num);
+        }
+    }
+
+    /**
+     * Undocumented method.  Do not use; internal-use only.
+     *
+     * <p>This method is for javassist.convert.TransformNew.
+     * It is called to update the stack map when
+     * the NEW opcode (and the following DUP) is removed. 
+     *
+     * @param where     the position of the removed NEW opcode.
+     */
+     public void removeNew(int where) throws CannotCompileException {
+         byte[] data = new NewRemover(this, where).doit();
+         this.set(data);
+    }
+
+    static class NewRemover extends SimpleCopy {
+        int posOfNew;
+
+        NewRemover(StackMap map, int where) {
+            super(map);
+            posOfNew = where;
+        }
+
+        public int stack(int pos, int offset, int num) {
+            return stackTypeInfoArray(pos, offset, num);
+        }
+
+        private int stackTypeInfoArray(int pos, int offset, int num) {
+            int p = pos;
+            int count = 0;
+            for (int k = 0; k < num; k++) {
+                byte tag = info[p];
+                if (tag == OBJECT)
+                    p += 3;
+                else if (tag == UNINIT) {
+                    int offsetOfNew = ByteArray.readU16bit(info, p + 1);
+                    if (offsetOfNew == posOfNew)
+                        count++;
+
+                    p += 3;
+                }
+                else
+                    p++;
+            }
+
+            writer.write16bit(num - count);
+            for (int k = 0; k < num; k++) {
+                byte tag = info[pos];
                 if (tag == OBJECT) {
-                    ByteArray.readU16bit(srcInfo, pos + 1);
+                    int clazz = ByteArray.readU16bit(info, pos + 1);
+                    objectVariable(pos, clazz);
                     pos += 3;
                 }
                 else if (tag == UNINIT) {
-                    ByteArray.readU16bit(srcInfo, pos + 1);
+                    int offsetOfNew = ByteArray.readU16bit(info, pos + 1);
+                    if (offsetOfNew != posOfNew)
+                        uninitialized(pos, offsetOfNew);
+
                     pos += 3;
                 }
-                else
+                else {
+                    typeInfo(pos, tag);
                     pos++;
+                }
             }
 
             return pos;
         }
     }
 
+    /**
+     * Prints this stack map.
+     */
+    public void print(java.io.PrintWriter out) {
+        new Printer(this, out).print();
+    }
+
+    static class Printer extends Walker {
+        private java.io.PrintWriter writer;
+
+        public Printer(StackMap map, java.io.PrintWriter out) {
+            super(map);
+            writer = out;
+        }
+
+        public void print() {
+            int num = ByteArray.readU16bit(info, 0);
+            writer.println(num + " entries");
+            visit();
+        }
+
+        public int locals(int pos, int offset, int num) {
+            writer.println("  * offset " + offset);
+            return super.locals(pos, offset, num);
+        }
+    }
+
     /**
      * Internal use only.
      */
@@ -218,6 +509,13 @@ public class StackMap extends AttributeInfo {
             output = new ByteArrayOutputStream();
         }
 
+        /**
+         * Converts the written data into a byte array.
+         */
+        public byte[] toByteArray() {
+            return output.toByteArray();
+        }
+
         /**
          * Converts to a <code>StackMap</code> attribute.
          */
index 2ca8bd72529f181eaa18f9b08625d6b3aa6902cd..f3cea6faa997d3e2c3ec8bd17bd2ce5ab799959c 100644 (file)
@@ -30,6 +30,7 @@ import javassist.CannotCompileException;
  * It was introduced by J2SE 6 for the process of verification by
  * typechecking.
  *
+ * @see StackMap
  * @since 3.4
  */
 public class StackMapTable extends AttributeInfo {
@@ -425,7 +426,8 @@ public class StackMapTable extends AttributeInfo {
     }
 
     /**
-     * Updates this stack map table when a new local variable is added.
+     * Updates this stack map table when a new local variable is inserted
+     * for a new parameter.
      *
      * @param index          the index of the added local variable.
      * @param tag            the type tag of that local variable. 
@@ -433,6 +435,7 @@ public class StackMapTable extends AttributeInfo {
      *                       in a constant pool table.  This should be zero unless the tag
      *                       is <code>ITEM_Object</code>.
      *
+     * @see javassist.CtBehavior#addParameter(javassist.CtClass)
      * @see #typeTagOf(char)
      * @see ConstPool
      */
@@ -469,6 +472,11 @@ public class StackMapTable extends AttributeInfo {
         }
     }
 
+    /* This implementation assumes that a local variable initially
+     * holding a parameter value is never changed to be a different
+     * type.
+     * 
+     */
     static class InsertLocal extends SimpleCopy {
         private int varIndex;
         private int varTag, varData;
index 6d2bf6858e88ee04e2a188d4002714608e4b9070..92cd37c6d48cc6f67403492fa1ff15da327dec19 100644 (file)
@@ -502,7 +502,16 @@ public class MapMaker extends Tracer {
     }
 
     private void writeVerifyTypeInfo(StackMap.Writer writer, ConstPool cp, TypeData[] types, int num) {
-        writer.write16bit(num);
+        int numDWord = 0;
+        for (int i = 0; i < num; i++) {
+            TypeData td = types[i];
+            if (td != null && td.is2WordType()) {
+                numDWord++;
+                i++;
+            }
+        }
+
+        writer.write16bit(num - numDWord);
         for (int i = 0; i < num; i++) {
             TypeData td = types[i];
             if (td == TOP)