]> source.dussan.org Git - javassist.git/commitdiff
modified javassist.convert.* to support the stack map table of Java 6.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Fri, 9 Feb 2007 18:05:21 +0000 (18:05 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Fri, 9 Feb 2007 18:05:21 +0000 (18:05 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@351 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

12 files changed:
.classpath
.project
build.xml
src/main/javassist/bytecode/ClassFileWriter.java
src/main/javassist/bytecode/CodeIterator.java
src/main/javassist/bytecode/StackMapTable.java
src/main/javassist/bytecode/stackmap/BasicBlock.java
src/main/javassist/bytecode/stackmap/StackAnalyzer.java
src/main/javassist/bytecode/stackmap/StackAnalyzerCore.java [new file with mode: 0644]
src/main/javassist/convert/TransformAccessArrayField.java
src/main/javassist/convert/TransformNew.java
src/test/test/Test.java [new file with mode: 0644]

index deae2f478f71a3e4c05465613f8f8f028eedbeb2..21f8fe5ac9dc87c07f90ec89123c715c3e4cd94c 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-       <classpathentry excluding="javassist/util/HotSwapper.java" kind="src" path="src/main"/>
-       <classpathentry kind="src" path="src/test"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="src" path="src/main"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/JVM 1.4.2"/>
        <classpathentry kind="output" path="build/classes"/>
 </classpath>
index 20b52261e30233a3d84cdc5e5d9709ffbaa4324b..4d88bda1b6f38ced476390a826c4cc546561fae1 100644 (file)
--- a/.project
+++ b/.project
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-       <name>javassist</name>
+       <name>jvst</name>
        <comment></comment>
        <projects>
        </projects>
                        <arguments>
                        </arguments>
                </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
-                       <triggers>full,incremental,</triggers>
-                       <arguments>
-                               <dictionary>
-                                       <key>LaunchConfigHandle</key>
-                                       <value>&lt;project&gt;/.externalToolBuilders/Ant.launch</value>
-                               </dictionary>
-                       </arguments>
-               </buildCommand>
        </buildSpec>
        <natures>
                <nature>org.eclipse.jdt.core.javanature</nature>
index a3dcadaf32cdb91fe8f0b9f384812aa59a5d29f4..214259f03dfdf06348730208e82e3bc7fa8163ad 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -109,7 +109,7 @@ to ${build.classes.dir}.</echo>
     <javadoc
            Locale="en_US"
            packagenames="javassist.*"
-           excludepackagenames="javassist.compiler.*,javassist.convert.*,javassist.scopedpool.*"
+           excludepackagenames="javassist.compiler.*,javassist.convert.*,javassist.scopedpool.*,javassist.bytecode.stackmap.*"
            sourcepath="src/main"
            defaultexcludes="yes"
            destdir="html"
index 528d98af47f69d513b11845feef4899e15f3fad6..2d667a864887ea97f402da5f701bc502afe88421 100644 (file)
@@ -109,7 +109,7 @@ public class ClassFileWriter {
             }
             else if (ai instanceof StackMapTable) {
                 out.println("<stack map table begin>");
-                StackMapTable.Writer.print((StackMapTable)ai, out);
+                StackMapTable.Printer.print((StackMapTable)ai, out);
                 out.println("<stack map table end>");
             }
             else if (ai instanceof SignatureAttribute) {
index 13948c9153a42f662e9daa0b70d47cdbfeb7c0c1..fbad5ee56b197dbc84a9c01586f33712173daba5 100644 (file)
@@ -671,6 +671,10 @@ public class CodeIterator implements Opcode {
         if (vta != null)
             vta.shiftPc(where, gapLength, exclusive);
 
+        StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag);
+        if (smt != null)
+            smt.shiftPc(where, gapLength, exclusive);
+
         return newcode;
     }
 
index a2fecaef8dd760a70279b9df1592dd66ec5b4b54..cb59efa2861f5a63e4548c3ea01ece32345fa597 100644 (file)
@@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
 import java.io.IOException;
 import java.util.Map;
+import javassist.CannotCompileException;
 
 /**
  * <code>stack_map</code> attribute.
@@ -54,8 +55,8 @@ public class StackMapTable extends AttributeInfo {
      * Makes a copy.
      *
      * @exception RuntimeCopyException  if a <code>BadBytecode</code>
-     *                          exception is thrown, it is
-     *                          converted into
+     *                          exception is thrown while copying,
+     *                          it is converted into
      *                          <code>RuntimeCopyException</code>.
      *
      */
@@ -136,17 +137,26 @@ public class StackMapTable extends AttributeInfo {
     /**
      * A code walker for a StackMapTable attribute.
      */
-    static class Walker {
+    public static class Walker {
         byte[] info;
         int numOfEntries;
 
+        /**
+         * Constructs a walker.
+         */
+        public Walker(StackMapTable smt) {
+            this(smt.get());
+        }
+
         /**
          * Constructs a walker.
          *
          * @param data      the <code>info</code> field of the
          *                  <code>attribute_info</code> structure.
+         *                  It can be obtained by <code>get()</code>
+         *                  in the <code>AttributeInfo</code> class.
          */
-        public Walker(byte[] data) {
+        Walker(byte[] data) {
             info = data;
             numOfEntries = ByteArray.readU16bit(data, 0);
         }
@@ -159,7 +169,7 @@ public class StackMapTable extends AttributeInfo {
         /**
          * Visits each entry of the stack map frames. 
          */
-        public final void parse() throws BadBytecode {
+        public void parse() throws BadBytecode {
             int n = numOfEntries;
             int pos = 2;
             for (int i = 0; i < n; i++)
@@ -213,9 +223,9 @@ public class StackMapTable extends AttributeInfo {
          *                  field of <code>attribute_info</code> structure.
          * @param offsetDelta
          */
-        public void sameFrame(int pos, int offsetDelta) {}
+        public void sameFrame(int pos, int offsetDelta) throws BadBytecode {}
 
-        private int sameLocals(int pos, int type) {
+        private int sameLocals(int pos, int type) throws BadBytecode {
             int offset;
             if (type < 128)
                 offset = type - 64;
@@ -247,7 +257,8 @@ public class StackMapTable extends AttributeInfo {
          *                          or <code>stack[0].offset</code>
          *                          if the tag is <code>UNINIT</code>.
          */
-        public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {}
+        public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData)
+            throws BadBytecode {}
 
         /**
          * Invoked if the visited frame is a <code>chop_frame</code>.
@@ -256,9 +267,9 @@ public class StackMapTable extends AttributeInfo {
          * @param offsetDelta
          * @param k                 the <cod>k</code> last locals are absent. 
          */
-        public void chopFrame(int pos, int offsetDelta, int k) {}
+        public void chopFrame(int pos, int offsetDelta, int k) throws BadBytecode {}
 
-        private int appendFrame(int pos, int type) {
+        private int appendFrame(int pos, int type) throws BadBytecode {
             int k = type - 251;
             int offset = ByteArray.readU16bit(info, pos + 1);
             int[] tags = new int[k];
@@ -290,9 +301,10 @@ public class StackMapTable extends AttributeInfo {
          * @param data          <code>locals[i].cpool_index</code>
          *                      or <cod>locals[i].offset</code>.
          */
-        public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {} 
+        public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data)
+            throws BadBytecode {} 
 
-        private int fullFrame(int pos) {
+        private int fullFrame(int pos) throws BadBytecode {
             int offset = ByteArray.readU16bit(info, pos + 1);
             int numOfLocals = ByteArray.readU16bit(info, pos + 3);
             int[] localsTags = new int[numOfLocals];
@@ -319,7 +331,8 @@ public class StackMapTable extends AttributeInfo {
          *                          or <code>stack[i].offset</code>
          */
         public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
-                              int[] stackTags, int[] stackData) {}
+                              int[] stackTags, int[] stackData)
+            throws BadBytecode {}
 
         private int verifyTypeInfo(int pos, int n, int[] tags, int[] data) {
             for (int i = 0; i < n; i++) {
@@ -335,15 +348,12 @@ public class StackMapTable extends AttributeInfo {
         }
     }
 
-    static class Copier extends Walker {
+    static class SimpleCopy extends Walker {
         private Writer writer;
-        private ConstPool srcPool, destPool;
 
-        public Copier(ConstPool src, byte[] data, ConstPool dest) {
+        public SimpleCopy(byte[] data) {
             super(data);
             writer = new Writer(data.length);
-            srcPool = src;
-            destPool = dest;
         }
 
         public byte[] doit() throws BadBytecode {
@@ -356,10 +366,7 @@ public class StackMapTable extends AttributeInfo {
         }
 
         public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
-            if (stackTag == OBJECT)
-                stackData = srcPool.copy(stackData, destPool, null); 
-
-            writer.sameLocals(offsetDelta, stackTag, stackData);
+            writer.sameLocals(offsetDelta, stackTag, copyData(stackTag, stackData));
         }
 
         public void chopFrame(int pos, int offsetDelta, int k) {
@@ -376,7 +383,32 @@ public class StackMapTable extends AttributeInfo {
                              stackTags, copyData(stackTags, stackData));
         }
 
-        private int[] copyData(int[] tags, int[] data) {
+        protected int copyData(int tag, int data) {
+            return data;
+        }
+
+        protected int[] copyData(int[] tags, int[] data) {
+            return data;
+        }
+    }
+
+    static class Copier extends SimpleCopy {
+        private ConstPool srcPool, destPool;
+
+        public Copier(ConstPool src, byte[] data, ConstPool dest) {
+            super(data);
+            srcPool = src;
+            destPool = dest;
+        }
+
+        protected int copyData(int tag, int data) {
+            if (tag == OBJECT)
+                return srcPool.copy(data, destPool, null); 
+            else
+                return data;
+        }
+
+        protected int[] copyData(int[] tags, int[] data) {
             int[] newData = new int[data.length];
             for (int i = 0; i < data.length; i++)
                 if (tags[i] == OBJECT)
@@ -391,22 +423,10 @@ public class StackMapTable extends AttributeInfo {
     /**
      * A writer of stack map tables.
      */
-    static class Writer {
+    public static class Writer {
         ByteArrayOutputStream output;
         int numOfEntries;
 
-        /**
-         * Prints the stack table map.
-         */
-        public static void print(StackMapTable smt, PrintWriter writer) {
-            try {
-                new Printer(smt.get(), writer).parse();
-            }
-            catch (BadBytecode e) {
-                writer.println(e.getMessage());
-            }
-        }
-
         /**
          * Constructs a writer.
          * @param size      the initial buffer size.
@@ -522,6 +542,7 @@ public class StackMapTable extends AttributeInfo {
                 writeTypeInfo(localTags[i], localData[i]);
 
             n = stackTags.length;
+            write16(n);
             for (int i = 0; i < n; i++)
                 writeTypeInfo(stackTags[i], stackData[i]);
         }
@@ -541,6 +562,18 @@ public class StackMapTable extends AttributeInfo {
     static class Printer extends Walker {
         private PrintWriter writer;
 
+        /**
+         * Prints the stack table map.
+         */
+        public static void print(StackMapTable smt, PrintWriter writer) {
+            try {
+                new Printer(smt.get(), writer).parse();
+            }
+            catch (BadBytecode e) {
+                writer.println(e.getMessage());
+            }
+        }
+
         Printer(byte[] data, PrintWriter pw) {
             super(data);
             writer = pw;
@@ -612,4 +645,166 @@ public class StackMapTable extends AttributeInfo {
             writer.println(msg);
         }
     }
+
+    void shiftPc(int where, int gapSize, boolean exclusive)
+        throws BadBytecode
+    {
+        new Shifter(this, where, gapSize, exclusive).doit();
+    }
+
+    static class Shifter extends Walker {
+        private StackMapTable stackMap;
+        private int where, gap;
+        private int position;
+        private byte[] updatedInfo;
+        private boolean exclusive;
+
+        public Shifter(StackMapTable smt, int where, int gap, boolean exclusive) {
+            super(smt);
+            stackMap = smt;
+            this.where = where;
+            this.gap = gap;
+            this.position = 0;
+            this.updatedInfo = null;
+            this.exclusive = exclusive;
+        }
+
+        public void doit() throws BadBytecode {
+            parse();
+            if (updatedInfo != null)
+                stackMap.set(updatedInfo);
+        }
+
+        public void sameFrame(int pos, int offsetDelta) {
+            update(pos, offsetDelta, 0, 251);
+        }
+
+        public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
+            update(pos, offsetDelta, 64, 247);
+        }
+
+        private void update(int pos, int offsetDelta, int base, int entry) {
+            int oldPos = position;
+            position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
+            boolean match;
+            if (exclusive)
+                match = oldPos < where  && where <= position;
+            else
+                match = oldPos <= where  && where < position;
+
+            if (match) {
+                int newDelta = offsetDelta + gap;
+                position += gap;
+                if (newDelta < 64)
+                    info[pos] = (byte)(newDelta + base);
+                else if (offsetDelta < 64) {
+                    byte[] newinfo = insertGap(info, pos, 2);
+                    newinfo[pos] = (byte)entry;
+                    ByteArray.write16bit(newDelta, info, pos + 1);
+                    updatedInfo = newinfo;
+                }
+                else
+                    ByteArray.write16bit(newDelta, info, pos + 1);
+            }
+        }
+
+        private static byte[] insertGap(byte[] info, int where, int gap) {
+            int len = info.length;
+            byte[] newinfo = new byte[len + gap];
+            for (int i = 0; i < len; i++)
+                newinfo[i + (i < where ? 0 : gap)] = info[i];
+
+            return newinfo;
+        }
+
+        public void chopFrame(int pos, int offsetDelta, int k) {
+            update(pos, offsetDelta);
+        }
+
+        public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
+            update(pos, offsetDelta);
+        }
+
+        public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
+                              int[] stackTags, int[] stackData) {
+            update(pos, offsetDelta);
+        }
+
+        private void update(int pos, int offsetDelta) {
+            int oldPos = position;
+            position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
+            boolean match;
+            if (exclusive)
+                match = oldPos < where  && where <= position;
+            else
+                match = oldPos <= where  && where < position;
+
+            if (match) {
+                int newDelta = offsetDelta + gap;
+                ByteArray.write16bit(newDelta, info, pos + 1);
+                position += gap;
+            }
+        }
+    }
+
+    /**
+     * Undocumented method.  Do not use; internal-use only.
+     *
+     * <p>This method is for javassist.convert.TransformNew.
+     * It is called to update the stack map table 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 {
+        try {
+            byte[] data = new NewRemover(this.get(), where).doit();
+            this.set(data);
+        }
+        catch (BadBytecode e) {
+            throw new CannotCompileException("bad stack map table", e);
+        }
+    }
+
+    static class NewRemover extends SimpleCopy {
+        int posOfNew;
+
+        public NewRemover(byte[] data, int pos) {
+            super(data);
+            posOfNew = pos;
+        }
+
+        public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
+            if (stackTag == UNINIT && stackData == posOfNew)
+                super.sameFrame(pos, offsetDelta);
+            else
+                super.sameLocals(pos, offsetDelta, stackTag, stackData);
+        }
+
+        public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
+                              int[] stackTags, int[] stackData) {
+            int n = stackTags.length - 1;
+            for (int i = 0; i < n; i++)
+                if (stackTags[i] == UNINIT && stackData[i] == posOfNew
+                    && stackTags[i + 1] == UNINIT && stackData[i + 1] == posOfNew) {
+                    n++;
+                    int[] stackTags2 = new int[n - 2];
+                    int[] stackData2 = new int[n - 2];
+                    int k = 0;
+                    for (int j = 0; j < n; j++)
+                        if (j == i)
+                            j++;
+                        else {
+                            stackTags2[k] = stackTags[j];
+                            stackData2[k++] = stackData[j];
+                        }
+
+                    stackTags = stackTags2;
+                    stackData = stackData2;
+                    break;
+                }
+
+            super.fullFrame(pos, offsetDelta, localTags, localData, stackTags, stackData);
+        }
+    }
 }
index d7076152dad87657d72fafbd71cbbfd3d51da3af..4f0111bfb1787240f22f3261a02f2dd7ec3fa308 100644 (file)
@@ -29,10 +29,10 @@ public class BasicBlock {
             int n = ltypes.length;
             for (int i = 0; i < n; i++)
                 if (ltypes[i] != localsTypes[i]) {
-                    localsTypes[i] = StackAnalyzer.EMPTY;
+                    localsTypes[i] = StackAnalyzerCore.EMPTY;
                     localsData[i] = null;
                 }
-                else if (ltypes[i] == StackAnalyzer.OBJECT
+                else if (ltypes[i] == StackAnalyzerCore.OBJECT
                          && !ldata[i].equals(localsData[i]))
                     ; // localsData[i] = ??;
         }
index 12b4892d9dc6a4beddc0c24da80202c27dce7683..264ffe86c0b0cd87f0cf98926cdc109c0983194a 100644 (file)
 package javassist.bytecode.stackmap;
 
-import javassist.bytecode.StackMapTable;
-import javassist.bytecode.ByteArray;
-import javassist.bytecode.Opcode;
 import javassist.bytecode.ConstPool;
-import javassist.bytecode.Descriptor;
-import javassist.bytecode.BadBytecode;
 
-public class StackAnalyzer {
-    private ConstPool cpool;
-    private int stackTop;
-    private int[] stackTypes;
-    private Object[] stackData;     // String or Integer
-
-    private int[] localsTypes;
-    private boolean[] localsUpdated;
-    private Object[] localsData;    // String or Integer
-
-    static final int EMPTY = -1;
-    static final int TOP = StackMapTable.TOP;
-    static final int INTEGER = StackMapTable.INTEGER;
-    static final int FLOAT = StackMapTable.FLOAT;
-    static final int DOUBLE = StackMapTable.DOUBLE;
-    static final int LONG = StackMapTable.LONG;
-    static final int NULL = StackMapTable.NULL;
-    static final int THIS = StackMapTable.THIS;
-    static final int OBJECT = StackMapTable.OBJECT;
-    static final int UNINIT = StackMapTable.UNINIT;
+public class StackAnalyzer extends StackAnalyzerCore {
 
     public StackAnalyzer(ConstPool cp, int maxStack, int maxLocals) {
-        cpool = cp;
-        stackTop = 0;
-        stackTypes = null;
-        localsTypes = null;
-        growStack(maxStack);
-        growLocals(maxLocals);
-    }
-
-    public void clearUpdatedFlags() {
-        boolean[] updated = localsUpdated;
-        for (int i = 0; i < updated.length; i++)
-            updated[i] = false;
-    }
-
-    public void growStack(int size) {
-        int oldSize;
-        int[] types = new int[size];
-        Object[] data = new Object[size];
-        if (stackTypes == null)
-            oldSize = 0;
-        else {
-            oldSize = stackTypes.length;
-            System.arraycopy(stackTypes, 0, types, 0, oldSize);
-            System.arraycopy(stackData, 0, data, 0, oldSize);
-        }
-
-        stackTypes = types;
-        stackData = data;
-        for (int i = oldSize; i < size; i++)
-            stackTypes[i] = EMPTY;
-    }
-
-    public void growLocals(int size) {
-        int oldSize;
-        int[] types = new int[size];
-        boolean[] updated = new boolean[size];
-        Object[] data = new Object[size];
-        if (localsTypes == null)
-            oldSize = 0;
-        else {
-            oldSize = localsTypes.length;
-            System.arraycopy(localsTypes, 0, types, 0, oldSize);
-            System.arraycopy(localsUpdated, 0, updated, 0, oldSize);
-            System.arraycopy(localsData, 0, data, 0, oldSize);
-        }
-
-        localsTypes = types;
-        localsUpdated = updated;
-        localsData = data;
-        for (int i = oldSize; i < size; i++)
-            localsTypes[i] = EMPTY;
-    }
-
-    public void pushType(int type, Object data) {
-        stackTypes[stackTop] = type;
-        stackData[stackTop++] = data;
-    }
-
-    /**
-     * @return      the size of the instruction at POS.
-     */
-    protected int doOpcode(int pos, byte[] code) throws BadBytecode {
-        int op = code[pos] & 0xff;
-        if (op < 96)
-            if (op < 54)
-                return doOpcode0_53(pos, code, op);
-            else
-                return doOpcode54_95(pos, code, op);
-        else
-            if (op < 148)
-                return doOpcode96_147(pos, code, op);
-            else
-                return doOpcode148_201(pos, code, op);
-    }
-
-    protected void visitBranch(int pos, byte[] code, int offset) {}
-    protected void visitGoto(int pos, byte[] code, int offset) {}
-    protected void visitTableSwitch(int pos, byte[] code, int n, int offsetPos, int defaultByte) {}
-    protected void visitLookupSwitch(int pos, byte[] code, int n, int pairsPos, int defaultByte) {}
-    protected void visitReturn(int pos, byte[] code) {}
-    protected void visitThrow(int pos, byte[] code) {}
-
-    /**
-     * Invoked when the visited instruction is jsr.
-     */
-    protected void visitJSR(int pos, byte[] code) throws BadBytecode {
-        throwBadBytecode(pos, "jsr");
-    }
-
-    /**
-     * Invoked when the visited instruction is ret.
-     */
-    protected void visitRET(int pos, byte[] code) throws BadBytecode {
-        throwBadBytecode(pos, "ret");
-    }
-
-    private void throwBadBytecode(int pos, String name) throws BadBytecode {
-        throw new BadBytecode(name + " at " + pos);
-    }
-
-    private int doOpcode0_53(int pos, byte[] code, int op) throws BadBytecode {
-        int[] stackTypes = this.stackTypes;
-        switch (op) {
-        case Opcode.NOP :
-            break;
-        case Opcode.ACONST_NULL :
-            stackTypes[stackTop++] = NULL;
-            break;
-        case Opcode.ICONST_M1 :
-        case Opcode.ICONST_0 :
-        case Opcode.ICONST_1 :
-        case Opcode.ICONST_2 :
-        case Opcode.ICONST_3 :
-        case Opcode.ICONST_4 :
-        case Opcode.ICONST_5 :
-            stackTypes[stackTop++] = INTEGER;
-            break;
-        case Opcode.LCONST_0 :
-        case Opcode.LCONST_1 :
-            stackTypes[stackTop++] = LONG;
-            stackTypes[stackTop++] = TOP;
-            break;
-        case Opcode.FCONST_0 :
-        case Opcode.FCONST_1 :
-        case Opcode.FCONST_2 :
-            stackTypes[stackTop++] = FLOAT;
-            break;
-        case Opcode.DCONST_0 :
-        case Opcode.DCONST_1 :
-            stackTypes[stackTop++] = DOUBLE;
-            stackTypes[stackTop++] = TOP;
-            break;
-        case Opcode.BIPUSH :
-        case Opcode.SIPUSH :
-            stackTypes[stackTop++] = INTEGER;
-            return op == Opcode.SIPUSH ? 3 : 2;
-        case Opcode.LDC :
-            doLDC(code[pos + 1] & 0xff);
-            return 2;
-        case Opcode.LDC_W :
-        case Opcode.LDC2_W :
-            doLDC(ByteArray.readU16bit(code, pos + 1));
-            return 3;
-        case Opcode.ILOAD :
-            return doXLOAD(INTEGER);
-        case Opcode.LLOAD :
-            return doXLOAD(LONG);
-        case Opcode.FLOAD :
-            return doXLOAD(FLOAT);
-        case Opcode.DLOAD :
-            return doXLOAD(DOUBLE);
-        case Opcode.ALOAD :
-            stackTypes[stackTop] = OBJECT;
-            stackData[stackTop++] = localsData[code[pos + 1] & 0xff];
-            return 2;
-        case Opcode.ILOAD_0 :
-        case Opcode.ILOAD_1 :
-        case Opcode.ILOAD_2 :
-        case Opcode.ILOAD_3 :
-            stackTypes[stackTop++] = INTEGER;
-            break;
-        case Opcode.LLOAD_0 :
-        case Opcode.LLOAD_1 :
-        case Opcode.LLOAD_2 :
-        case Opcode.LLOAD_3 :
-            stackTypes[stackTop++] = LONG;
-            stackTypes[stackTop++] = TOP;
-            break;
-        case Opcode.FLOAD_0 :
-        case Opcode.FLOAD_1 :
-        case Opcode.FLOAD_2 :
-        case Opcode.FLOAD_3 :
-            stackTypes[stackTop++] = FLOAT;
-            break;
-        case Opcode.DLOAD_0 :
-        case Opcode.DLOAD_1 :
-        case Opcode.DLOAD_2 :
-        case Opcode.DLOAD_3 :
-            stackTypes[stackTop++] = DOUBLE;
-            stackTypes[stackTop++] = TOP;
-            break;
-        case Opcode.ALOAD_0 :
-        case Opcode.ALOAD_1 :
-        case Opcode.ALOAD_2 :
-        case Opcode.ALOAD_3 :
-            stackTypes[stackTop] = OBJECT;
-            stackData[stackTop++] = localsData[op - Opcode.ALOAD_0];
-            break;
-        case Opcode.IALOAD :
-            stackTypes[--stackTop - 1] = INTEGER;
-            break;
-        case Opcode.LALOAD :
-            stackTypes[stackTop - 2] = LONG;
-            stackTypes[stackTop - 1] = TOP;
-            break;
-        case Opcode.FALOAD :
-            stackTypes[--stackTop - 1] = FLOAT;
-            break;
-        case Opcode.DALOAD :
-            stackTypes[stackTop - 2] = DOUBLE;
-            stackTypes[stackTop - 1] = TOP;
-            break;
-        case Opcode.AALOAD : {
-            int s = --stackTop - 1;
-            stackTypes[s] = OBJECT;
-            Object data = stackData[s];
-            if (data != null && data instanceof String)
-                stackData[s] = getDerefType((String)data);
-            else
-                throw new BadBytecode("bad AALOAD");
-
-            break; }
-        case Opcode.BALOAD :
-        case Opcode.CALOAD :
-        case Opcode.SALOAD :
-            stackTypes[--stackTop - 1] = INTEGER;
-            break;
-        default :
-            throw new RuntimeException("fatal");
-        }
-
-        return 1;
-    }
-
-    private void doLDC(int index) {
-        int[] stackTypes = this.stackTypes;
-        int tag = cpool.getTag(index);
-        if (tag == ConstPool.CONST_String) {
-            stackTypes[stackTop] = OBJECT;
-            stackData[stackTop++] = "java/lang/String";
-        }
-        else if (tag == ConstPool.CONST_Integer)
-            stackTypes[stackTop++] = INTEGER;
-        else if (tag == ConstPool.CONST_Float)
-            stackTypes[stackTop++] = FLOAT;
-        else if (tag == ConstPool.CONST_Long) {
-            stackTypes[stackTop++] = LONG;
-            stackTypes[stackTop++] = TOP;
-        }
-        else if (tag == ConstPool.CONST_Double) {
-            stackTypes[stackTop++] = DOUBLE;
-            stackTypes[stackTop++] = TOP;
-        }
-        else if (tag == ConstPool.CONST_Class) {
-            stackTypes[stackTop] = OBJECT;
-            stackData[stackTop++] = "java/lang/Class";
-        }
-        else
-            throw new RuntimeException("bad LDC: " + tag);
-    }
-
-    private int doXLOAD(int type) {
-        int[] stackTypes = this.stackTypes;
-        stackTypes[stackTop++] = type;
-        if (type == LONG || type == DOUBLE)
-            stackTypes[stackTop++] = TOP;
-
-        return 2;
-    }
-
-    private String getDerefType(String type) throws BadBytecode {
-        if (type.charAt(0) == '[') {
-            String type2 = type.substring(1);
-            if (type2.length() > 0) {
-                char c = type2.charAt(0);
-                if (c == '[')
-                    return type2;
-                else if (c == 'L')
-                    return type2.substring(1, type.length() - 2);
-                else
-                    return type2;
-            }
-        }
-
-        throw new BadBytecode("bad array type for AALOAD: " + type);
-    }
-
-    private int doOpcode54_95(int pos, byte[] code, int op) {
-        int[] localsTypes = this.localsTypes;
-        int[] stackTypes = this.stackTypes;
-        switch (op) {
-        case Opcode.ISTORE :
-            return doXSTORE(pos, code, INTEGER);
-        case Opcode.LSTORE :
-            return doXSTORE(pos, code, LONG);
-        case Opcode.FSTORE :
-            return doXSTORE(pos, code, FLOAT);
-        case Opcode.DSTORE :
-            return doXSTORE(pos, code, DOUBLE);
-        case Opcode.ASTORE :
-            return doXSTORE(pos, code, OBJECT);
-        case Opcode.ISTORE_0 :
-        case Opcode.ISTORE_1 :
-        case Opcode.ISTORE_2 :
-        case Opcode.ISTORE_3 :
-          { int var = op - Opcode.ISTORE_0;
-            localsTypes[var] = INTEGER;
-            localsUpdated[var] = true; }
-            stackTop--;
-            break;
-        case Opcode.LSTORE_0 :
-        case Opcode.LSTORE_1 :
-        case Opcode.LSTORE_2 :
-        case Opcode.LSTORE_3 :
-          { int var = op - Opcode.LSTORE_0;
-            localsTypes[var] = LONG;
-            localsTypes[var + 1] = TOP;
-            localsUpdated[var] = true; }
-            stackTop -= 2;
-            break;
-        case Opcode.FSTORE_0 :
-        case Opcode.FSTORE_1 :
-        case Opcode.FSTORE_2 :
-        case Opcode.FSTORE_3 :
-          { int var = op - Opcode.FSTORE_0;
-            localsTypes[var] = FLOAT;
-            localsUpdated[var] = true; }
-            stackTop--;
-            break;
-        case Opcode.DSTORE_0 :
-        case Opcode.DSTORE_1 :
-        case Opcode.DSTORE_2 :
-        case Opcode.DSTORE_3 :
-          { int var = op - Opcode.DSTORE_0;
-            localsTypes[var] = DOUBLE;
-            localsTypes[var + 1] = TOP;
-            localsUpdated[var] = true; }
-            stackTop -= 2;
-            break;
-        case Opcode.ASTORE_0 :
-        case Opcode.ASTORE_1 :
-        case Opcode.ASTORE_2 :
-        case Opcode.ASTORE_3 :
-          { int var = op - Opcode.ASTORE_0;
-            localsTypes[var] = OBJECT;
-            localsUpdated[var] = true;
-            localsData[var] = stackData[--stackTop]; }
-            break;
-        case Opcode.IASTORE :
-        case Opcode.LASTORE :
-        case Opcode.FASTORE :
-        case Opcode.DASTORE :
-        case Opcode.AASTORE :
-        case Opcode.BASTORE :
-        case Opcode.CASTORE :
-        case Opcode.SASTORE :
-            stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
-            break;
-        case Opcode.POP :
-            stackTop--;
-            break;
-        case Opcode.POP2 :
-            stackTop -= 2;
-            break;
-        case Opcode.DUP : {
-            int sp = stackTop;
-            stackTypes[sp] = stackTypes[sp - 1];
-            stackData[sp] = stackData[sp - 1];
-            stackTop = sp + 1;
-            break; }
-        case Opcode.DUP_X1 :
-        case Opcode.DUP_X2 : {
-            int len = op - Opcode.DUP_X1 + 2;
-            doDUP_XX(1, len);
-            int sp = stackTop;
-            stackTypes[sp - len] = stackTypes[sp];
-            stackData[sp - len] = stackData[sp];
-            stackTop = sp + 1;
-            break; }
-        case Opcode.DUP2 :
-            doDUP_XX(2, 2);
-            stackTop += 2;
-            break;
-        case Opcode.DUP2_X1 :
-        case Opcode.DUP2_X2 : {
-            int len = op - Opcode.DUP2_X1 + 3;
-            doDUP_XX(2, len);
-            Object[] stackData = this.stackData;
-            int sp = stackTop;
-            stackTypes[sp - len] = stackTypes[sp];
-            stackData[sp - len] = stackData[sp];
-            stackTypes[sp - len + 1] = stackTypes[sp + 1];
-            stackData[sp - len + 1] = stackData[sp + 1];
-            stackTop = sp + 2; 
-            break; }
-        case Opcode.SWAP : {
-            Object[] stackData = this.stackData;
-            int sp = stackTop - 1;
-            int t = stackTypes[sp];
-            Object d = stackData[sp];
-            stackTypes[sp] = stackTypes[sp - 1];
-            stackData[sp] = stackData[sp - 1];
-            stackTypes[sp - 1] = t;
-            stackData[sp - 1] = d;
-            break; }
-        default :
-            throw new RuntimeException("fatal");
-        }
-
-        return 1;
-    }
-
-    private int doXSTORE(int pos, byte[] code, int type) {
-        int index = code[pos + 1] & 0xff;
-        return doXSTORE(index, type);
-    }
-
-    private int doXSTORE(int index, int type) {
-        stackTop--;
-        localsTypes[index] = type;
-        localsUpdated[index] = true;
-        if (type == LONG || type == DOUBLE) {
-            stackTop--;
-            localsTypes[index + 1] = TOP;
-        }
-        else if (type == OBJECT)
-            localsData[index] = stackData[stackTop];
-
-        return 2;
-    }
-
-    private void doDUP_XX(int delta, int len) {
-        int types[] = stackTypes;
-        Object data[] = stackData;
-        int sp = stackTop;
-        int end = sp - len;
-        while (sp > end) {
-            types[sp + delta] = types[sp];
-            data[sp + delta] = data[sp];
-            sp--;
-        }
-    }
-
-    private int doOpcode96_147(int pos, byte[] code, int op) {
-        if (op <= Opcode.LXOR) {    // IADD...LXOR
-            stackTop -= Opcode.STACK_GROW[op];
-            return 1;
-        }
-
-        switch (op) {
-        case Opcode.IINC :
-            return 3;
-        case Opcode.I2L :
-            stackTypes[stackTop] = LONG;
-            stackTypes[stackTop - 1] = TOP;
-            stackTop++;
-            break;
-        case Opcode.I2F :
-            stackTypes[stackTop - 1] = FLOAT;
-            break;
-        case Opcode.I2D :
-            stackTypes[stackTop] = DOUBLE;
-            stackTypes[stackTop - 1] = TOP;
-            stackTop++;
-            break;
-        case Opcode.L2I :
-            stackTypes[--stackTop - 1] = INTEGER;
-            break;
-        case Opcode.L2F :
-            stackTypes[--stackTop - 1] = FLOAT;
-            break;
-        case Opcode.L2D :
-            stackTypes[stackTop - 1] = DOUBLE;
-            break;
-        case Opcode.F2I :
-            stackTypes[stackTop - 1] = INTEGER;
-            break;
-        case Opcode.F2L :
-            stackTypes[stackTop - 1] = TOP;
-            stackTypes[stackTop++] = LONG;
-            break;
-        case Opcode.F2D :
-            stackTypes[stackTop - 1] = TOP;
-            stackTypes[stackTop++] = DOUBLE;
-            break;
-        case Opcode.D2I :
-            stackTypes[--stackTop - 1] = INTEGER;
-            break;
-        case Opcode.D2L :
-            stackTypes[stackTop - 1] = LONG;
-            break;
-        case Opcode.D2F :
-            stackTypes[--stackTop - 1] = FLOAT;
-            break;
-        case Opcode.I2B :
-        case Opcode.I2C :
-        case Opcode.I2S :
-            break;
-        default :
-            throw new RuntimeException("fatal");
-        }
-
-        return 1;
-    }
-
-    private int doOpcode148_201(int pos, byte[] code, int op) throws BadBytecode {
-        switch (op) {
-        case Opcode.LCMP :
-            stackTypes[stackTop - 4] = INTEGER;
-            stackTop -= 3;
-            break;
-        case Opcode.FCMPL :
-        case Opcode.FCMPG :
-            stackTypes[--stackTop - 1] = INTEGER;
-            break;
-        case Opcode.DCMPL :
-        case Opcode.DCMPG :
-            stackTypes[stackTop - 4] = INTEGER;
-            stackTop -= 3;
-            break;
-        case Opcode.IFEQ :
-        case Opcode.IFNE :
-        case Opcode.IFLT :
-        case Opcode.IFGE :
-        case Opcode.IFGT :
-        case Opcode.IFLE :
-            stackTop--;     // branch
-            visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
-            return 3;
-        case Opcode.IF_ICMPEQ :
-        case Opcode.IF_ICMPNE :
-        case Opcode.IF_ICMPLT :
-        case Opcode.IF_ICMPGE :
-        case Opcode.IF_ICMPGT :
-        case Opcode.IF_ICMPLE :
-        case Opcode.IF_ACMPEQ :
-        case Opcode.IF_ACMPNE :
-            stackTop -= 2;  // branch
-            visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
-            return 3;
-        case Opcode.GOTO :
-            visitGoto(pos, code, ByteArray.readS16bit(code, pos + 1));
-            return 3;       // branch
-        case Opcode.JSR :
-            stackTypes[stackTop++] = TOP;       // not allowed?
-            visitJSR(pos, code);
-            return 3;       // branch
-        case Opcode.RET :
-            visitRET(pos, code);
-            return 2;                           // not allowed?
-        case Opcode.TABLESWITCH : {
-            stackTop--;     // branch
-            int pos2 = (pos & ~3) + 8;
-            int low = ByteArray.read32bit(code, pos2);
-            int high = ByteArray.read32bit(code, pos2 + 4);
-            int n = high - low + 1;
-            visitTableSwitch(pos, code, n, pos2 + 8, ByteArray.read32bit(code, pos2 - 4));
-            return n * 4 + 16 - (pos & 3); }
-        case Opcode.LOOKUPSWITCH : {
-            stackTop--;     // branch
-            int pos2 = (pos & ~3) + 8;
-            int n = ByteArray.read32bit(code, pos2);
-            visitLookupSwitch(pos, code, n, pos2 + 4, ByteArray.read32bit(code, pos2 - 4));
-            return n * 8 + 12 - (pos & 3); }
-        case Opcode.IRETURN :
-            stackTop--;
-            visitReturn(pos, code);
-            break;
-        case Opcode.LRETURN :
-            stackTop -= 2;
-            visitReturn(pos, code);
-            break;
-        case Opcode.FRETURN :
-            stackTop--;
-            visitReturn(pos, code);
-            break;
-        case Opcode.DRETURN :
-            stackTop -= 2;
-            visitReturn(pos, code);
-            break;
-        case Opcode.ARETURN :
-            stackTop--;
-            visitReturn(pos, code);
-            break;
-        case Opcode.RETURN :
-            visitReturn(pos, code);
-            break;
-        case Opcode.GETSTATIC :
-            return doFieldAccess(pos, code, true);
-        case Opcode.PUTSTATIC :
-            return doFieldAccess(pos, code, false);
-        case Opcode.GETFIELD :
-            stackTop--;
-            return doFieldAccess(pos, code, true);
-        case Opcode.PUTFIELD :
-            stackTop--;
-            return doFieldAccess(pos, code, false);
-        case Opcode.INVOKEVIRTUAL :
-        case Opcode.INVOKESPECIAL :
-            return doInvokeMethod(pos, code, 1);
-        case Opcode.INVOKESTATIC :
-            return doInvokeMethod(pos, code, 0);
-        case Opcode.INVOKEINTERFACE :
-            return doInvokeIntfMethod(pos, code, 1);
-        case 186 :
-            throw new RuntimeException("bad opcode 186");
-        case Opcode.NEW : {
-            int i = ByteArray.readU16bit(code, pos + 1);
-            stackTypes[stackTop - 1] = UNINIT;
-            stackData[stackTop - 1] = new Integer(pos);
-            return 3; }
-        case Opcode.NEWARRAY :
-            return doNEWARRAY(pos, code);
-        case Opcode.ANEWARRAY : {
-            int i = ByteArray.readU16bit(code, pos + 1);
-            stackTypes[stackTop - 1] = OBJECT;
-            stackData[stackTop - 1]
-                      = "[L" + cpool.getClassInfo(i).replace('.', '/') + ";";
-            return 3; }
-        case Opcode.ARRAYLENGTH :
-            stackTypes[stackTop - 1] = INTEGER;
-            break;
-        case Opcode.ATHROW :
-            stackTop--;         // branch?
-            visitThrow(pos, code);
-            break;
-        case Opcode.CHECKCAST : {
-            int i = ByteArray.readU16bit(code, pos + 1);
-            stackData[stackTop - 1] = cpool.getClassInfo(i);
-            return 3; }
-        case Opcode.INSTANCEOF :
-            stackTypes[stackTop - 1] = INTEGER;
-            return 3;
-        case Opcode.MONITORENTER :
-        case Opcode.MONITOREXIT :
-            stackTop--;
-            break;
-        case Opcode.WIDE :
-            return doWIDE(pos, code);
-        case Opcode.MULTIANEWARRAY :
-            return doMultiANewArray(pos, code);
-        case Opcode.IFNULL :
-        case Opcode.IFNONNULL :
-            stackTop--;         // branch
-            visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
-            return 3;
-        case Opcode.GOTO_W :
-            visitGoto(pos, code, ByteArray.read32bit(code, pos + 1));
-            return 5;           // branch
-        case Opcode.JSR_W :
-            stackTypes[stackTop++] = TOP;       // not allowed?
-            visitJSR(pos, code);
-            return 5;
-        }
-        return 1;
-    }
-
-    private int doWIDE(int pos, byte[] code) {
-        int op = code[pos + 1] & 0xff;
-        switch (op) {
-        case Opcode.ILOAD :
-            doXLOAD(INTEGER);
-            break;
-        case Opcode.LLOAD :
-            doXLOAD(LONG);
-            break;
-        case Opcode.FLOAD :
-            doXLOAD(FLOAT);
-            break;
-        case Opcode.DLOAD :
-            doXLOAD(DOUBLE);
-            break;
-        case Opcode.ALOAD :
-            stackTypes[stackTop] = OBJECT;
-            stackData[stackTop++] = localsData[ByteArray.readU16bit(code, pos)];
-            break;
-        case Opcode.ISTORE :
-            return doWIDE_STORE(pos, code, INTEGER);
-        case Opcode.LSTORE :
-            return doWIDE_STORE(pos, code, LONG);
-        case Opcode.FSTORE :
-            return doWIDE_STORE(pos, code, FLOAT);
-        case Opcode.DSTORE :
-            return doWIDE_STORE(pos, code, DOUBLE);
-        case Opcode.ASTORE :
-            return doWIDE_STORE(pos, code, OBJECT);
-        case Opcode.IINC :
-            return 6;
-        case Opcode.RET :
-            break;
-        default :
-            throw new RuntimeException("bad WIDE instruction: " + op);
-        }
-
-        return 4;
-    }
-
-    private int doWIDE_STORE(int pos, byte[] code, int type) {
-        int index = ByteArray.readU16bit(code, pos);
-        return doXSTORE(index, type);
-    }
-
-    private int doFieldAccess(int pos, byte[] code, boolean isGet) {
-        int index = ByteArray.readU16bit(code, pos + 1);
-        String desc = cpool.getFieldrefType(index);
-        if (isGet)
-            pushMemberType(desc);
-        else
-            stackTop -= Descriptor.dataSize(desc);
-
-        return 3;
-    }
-
-    private int doNEWARRAY(int pos, byte[] code) {
-        int s = stackTop - 1;
-        stackTypes[s] = OBJECT;
-        String type;
-        switch (code[pos + 1] & 0xff) {
-        case Opcode.T_BOOLEAN :
-            type = "[Z";
-            break;
-        case Opcode.T_CHAR :
-            type = "[C";
-            break;
-        case Opcode.T_FLOAT :
-            type = "[F";
-            break;
-        case Opcode.T_DOUBLE :
-            type = "[D";
-            break;
-        case Opcode.T_BYTE :
-            type = "[B";
-            break;
-        case Opcode.T_SHORT :
-            type = "[S";
-            break;
-        case Opcode.T_INT :
-            type = "[I";
-            break;
-        case Opcode.T_LONG :
-            type = "[J";
-            break;
-        default :
-            throw new RuntimeException("bad newarray");
-        }
-
-        stackData[s] = type;
-        return 2;
-    }
-
-    private int doMultiANewArray(int pos, byte[] code) {
-        int i = ByteArray.readU16bit(code, pos + 1);
-        int dim = code[pos + 3] & 0xff;
-        stackTop -= dim - 1;
-        String type = cpool.getClassInfo(i);
-        StringBuffer sbuf = new StringBuffer();
-        while (dim-- > 0)
-            sbuf.append('[');
-
-        sbuf.append('L').append(type.replace('.', '/')).append(';');
-        stackTypes[stackTop - 1] = OBJECT;
-        stackData[stackTop - 1] = sbuf.toString(); 
-        return 4;
-    }
-
-    private int doInvokeMethod(int pos, byte[] code, int targetSize) {
-        int i = ByteArray.readU16bit(code, pos + 1);
-        String desc = cpool.getMethodrefType(i);
-        stackTop -= Descriptor.paramSize(desc) + targetSize;
-        pushMemberType(desc);
-        return 3;
-    }
-
-    private int doInvokeIntfMethod(int pos, byte[] code, int targetSize) {
-        int i = ByteArray.readU16bit(code, pos + 1);
-        String desc = cpool.getInterfaceMethodrefType(i);
-        stackTop -= Descriptor.paramSize(desc) + targetSize;
-        pushMemberType(desc);
-        return 5;
-    }
-
-    private void pushMemberType(String descriptor) {
-        int top = 0;
-        if (descriptor.charAt(0) == '(') {
-            top = descriptor.indexOf(')') + 1;
-            if (top < 1)
-                throw new IndexOutOfBoundsException("bad descriptor: "
-                                                    + descriptor);
-        }
-
-        int[] types = stackTypes;
-        int index = stackTop;
-        switch (descriptor.charAt(top)) {
-        case '[' :
-            types[index] = OBJECT;
-            stackData[index] = descriptor.substring(top);
-            break;
-        case 'L' :
-            types[index] = OBJECT;
-            stackData[index] = descriptor.substring(top + 1,
-                                        descriptor.indexOf(';', top));
-            break;
-        case 'J' :
-            types[index] = LONG;
-            types[index + 1] = TOP;
-            stackTop += 2;
-            return;
-        case 'F' :
-            types[index] = FLOAT;
-            break;
-        case 'D' :
-            types[index] = DOUBLE;
-            types[index + 1] = TOP;
-            stackTop += 2;
-            return;
-        case 'V' :
-            return;
-        default : // C, B, S, I, Z
-            types[index] = INTEGER;
-            break;
-        }
-
-        stackTop++;
+        super(cp, maxStack, maxLocals);
     }
 }
diff --git a/src/main/javassist/bytecode/stackmap/StackAnalyzerCore.java b/src/main/javassist/bytecode/stackmap/StackAnalyzerCore.java
new file mode 100644 (file)
index 0000000..c3c79c8
--- /dev/null
@@ -0,0 +1,846 @@
+package javassist.bytecode.stackmap;
+
+import javassist.bytecode.StackMapTable;
+import javassist.bytecode.ByteArray;
+import javassist.bytecode.Opcode;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.Descriptor;
+import javassist.bytecode.BadBytecode;
+
+public class StackAnalyzerCore {
+    private ConstPool cpool;
+    private int stackTop;
+    private int[] stackTypes;
+    private Object[] stackData;     // String or Integer
+
+    private int[] localsTypes;
+    private boolean[] localsUpdated;
+    private Object[] localsData;    // String or Integer
+
+    static final int EMPTY = -1;
+    static final int TOP = StackMapTable.TOP;
+    static final int INTEGER = StackMapTable.INTEGER;
+    static final int FLOAT = StackMapTable.FLOAT;
+    static final int DOUBLE = StackMapTable.DOUBLE;
+    static final int LONG = StackMapTable.LONG;
+    static final int NULL = StackMapTable.NULL;
+    static final int THIS = StackMapTable.THIS;
+    static final int OBJECT = StackMapTable.OBJECT;
+    static final int UNINIT = StackMapTable.UNINIT;
+
+    public StackAnalyzerCore(ConstPool cp, int maxStack, int maxLocals) {
+        cpool = cp;
+        stackTop = 0;
+        stackTypes = null;
+        localsTypes = null;
+        growStack(maxStack);
+        growLocals(maxLocals);
+    }
+
+    public void clearUpdatedFlags() {
+        boolean[] updated = localsUpdated;
+        for (int i = 0; i < updated.length; i++)
+            updated[i] = false;
+    }
+
+    public void growStack(int size) {
+        int oldSize;
+        int[] types = new int[size];
+        Object[] data = new Object[size];
+        if (stackTypes == null)
+            oldSize = 0;
+        else {
+            oldSize = stackTypes.length;
+            System.arraycopy(stackTypes, 0, types, 0, oldSize);
+            System.arraycopy(stackData, 0, data, 0, oldSize);
+        }
+
+        stackTypes = types;
+        stackData = data;
+        for (int i = oldSize; i < size; i++)
+            stackTypes[i] = EMPTY;
+    }
+
+    public void growLocals(int size) {
+        int oldSize;
+        int[] types = new int[size];
+        boolean[] updated = new boolean[size];
+        Object[] data = new Object[size];
+        if (localsTypes == null)
+            oldSize = 0;
+        else {
+            oldSize = localsTypes.length;
+            System.arraycopy(localsTypes, 0, types, 0, oldSize);
+            System.arraycopy(localsUpdated, 0, updated, 0, oldSize);
+            System.arraycopy(localsData, 0, data, 0, oldSize);
+        }
+
+        localsTypes = types;
+        localsUpdated = updated;
+        localsData = data;
+        for (int i = oldSize; i < size; i++)
+            localsTypes[i] = EMPTY;
+    }
+
+    public void pushType(int type, Object data) {
+        stackTypes[stackTop] = type;
+        stackData[stackTop++] = data;
+    }
+
+    /**
+     * @return      the size of the instruction at POS.
+     */
+    protected int doOpcode(int pos, byte[] code) throws BadBytecode {
+        int op = code[pos] & 0xff;
+        if (op < 96)
+            if (op < 54)
+                return doOpcode0_53(pos, code, op);
+            else
+                return doOpcode54_95(pos, code, op);
+        else
+            if (op < 148)
+                return doOpcode96_147(pos, code, op);
+            else
+                return doOpcode148_201(pos, code, op);
+    }
+
+    protected void visitBranch(int pos, byte[] code, int offset) {}
+    protected void visitGoto(int pos, byte[] code, int offset) {}
+    protected void visitTableSwitch(int pos, byte[] code, int n, int offsetPos, int defaultByte) {}
+    protected void visitLookupSwitch(int pos, byte[] code, int n, int pairsPos, int defaultByte) {}
+    protected void visitReturn(int pos, byte[] code) {}
+    protected void visitThrow(int pos, byte[] code) {}
+
+    /**
+     * Invoked when the visited instruction is jsr.
+     */
+    protected void visitJSR(int pos, byte[] code) throws BadBytecode {
+        throwBadBytecode(pos, "jsr");
+    }
+
+    /**
+     * Invoked when the visited instruction is ret.
+     */
+    protected void visitRET(int pos, byte[] code) throws BadBytecode {
+        throwBadBytecode(pos, "ret");
+    }
+
+    private void throwBadBytecode(int pos, String name) throws BadBytecode {
+        throw new BadBytecode(name + " at " + pos);
+    }
+
+    private int doOpcode0_53(int pos, byte[] code, int op) throws BadBytecode {
+        int[] stackTypes = this.stackTypes;
+        switch (op) {
+        case Opcode.NOP :
+            break;
+        case Opcode.ACONST_NULL :
+            stackTypes[stackTop++] = NULL;
+            break;
+        case Opcode.ICONST_M1 :
+        case Opcode.ICONST_0 :
+        case Opcode.ICONST_1 :
+        case Opcode.ICONST_2 :
+        case Opcode.ICONST_3 :
+        case Opcode.ICONST_4 :
+        case Opcode.ICONST_5 :
+            stackTypes[stackTop++] = INTEGER;
+            break;
+        case Opcode.LCONST_0 :
+        case Opcode.LCONST_1 :
+            stackTypes[stackTop++] = LONG;
+            stackTypes[stackTop++] = TOP;
+            break;
+        case Opcode.FCONST_0 :
+        case Opcode.FCONST_1 :
+        case Opcode.FCONST_2 :
+            stackTypes[stackTop++] = FLOAT;
+            break;
+        case Opcode.DCONST_0 :
+        case Opcode.DCONST_1 :
+            stackTypes[stackTop++] = DOUBLE;
+            stackTypes[stackTop++] = TOP;
+            break;
+        case Opcode.BIPUSH :
+        case Opcode.SIPUSH :
+            stackTypes[stackTop++] = INTEGER;
+            return op == Opcode.SIPUSH ? 3 : 2;
+        case Opcode.LDC :
+            doLDC(code[pos + 1] & 0xff);
+            return 2;
+        case Opcode.LDC_W :
+        case Opcode.LDC2_W :
+            doLDC(ByteArray.readU16bit(code, pos + 1));
+            return 3;
+        case Opcode.ILOAD :
+            return doXLOAD(INTEGER);
+        case Opcode.LLOAD :
+            return doXLOAD(LONG);
+        case Opcode.FLOAD :
+            return doXLOAD(FLOAT);
+        case Opcode.DLOAD :
+            return doXLOAD(DOUBLE);
+        case Opcode.ALOAD :
+            stackTypes[stackTop] = OBJECT;
+            stackData[stackTop++] = localsData[code[pos + 1] & 0xff];
+            return 2;
+        case Opcode.ILOAD_0 :
+        case Opcode.ILOAD_1 :
+        case Opcode.ILOAD_2 :
+        case Opcode.ILOAD_3 :
+            stackTypes[stackTop++] = INTEGER;
+            break;
+        case Opcode.LLOAD_0 :
+        case Opcode.LLOAD_1 :
+        case Opcode.LLOAD_2 :
+        case Opcode.LLOAD_3 :
+            stackTypes[stackTop++] = LONG;
+            stackTypes[stackTop++] = TOP;
+            break;
+        case Opcode.FLOAD_0 :
+        case Opcode.FLOAD_1 :
+        case Opcode.FLOAD_2 :
+        case Opcode.FLOAD_3 :
+            stackTypes[stackTop++] = FLOAT;
+            break;
+        case Opcode.DLOAD_0 :
+        case Opcode.DLOAD_1 :
+        case Opcode.DLOAD_2 :
+        case Opcode.DLOAD_3 :
+            stackTypes[stackTop++] = DOUBLE;
+            stackTypes[stackTop++] = TOP;
+            break;
+        case Opcode.ALOAD_0 :
+        case Opcode.ALOAD_1 :
+        case Opcode.ALOAD_2 :
+        case Opcode.ALOAD_3 :
+            stackTypes[stackTop] = OBJECT;
+            stackData[stackTop++] = localsData[op - Opcode.ALOAD_0];
+            break;
+        case Opcode.IALOAD :
+            stackTypes[--stackTop - 1] = INTEGER;
+            break;
+        case Opcode.LALOAD :
+            stackTypes[stackTop - 2] = LONG;
+            stackTypes[stackTop - 1] = TOP;
+            break;
+        case Opcode.FALOAD :
+            stackTypes[--stackTop - 1] = FLOAT;
+            break;
+        case Opcode.DALOAD :
+            stackTypes[stackTop - 2] = DOUBLE;
+            stackTypes[stackTop - 1] = TOP;
+            break;
+        case Opcode.AALOAD : {
+            int s = --stackTop - 1;
+            stackTypes[s] = OBJECT;
+            Object data = stackData[s];
+            if (data != null && data instanceof String)
+                stackData[s] = getDerefType((String)data);
+            else
+                throw new BadBytecode("bad AALOAD");
+
+            break; }
+        case Opcode.BALOAD :
+        case Opcode.CALOAD :
+        case Opcode.SALOAD :
+            stackTypes[--stackTop - 1] = INTEGER;
+            break;
+        default :
+            throw new RuntimeException("fatal");
+        }
+
+        return 1;
+    }
+
+    private void doLDC(int index) {
+        int[] stackTypes = this.stackTypes;
+        int tag = cpool.getTag(index);
+        if (tag == ConstPool.CONST_String) {
+            stackTypes[stackTop] = OBJECT;
+            stackData[stackTop++] = "java/lang/String";
+        }
+        else if (tag == ConstPool.CONST_Integer)
+            stackTypes[stackTop++] = INTEGER;
+        else if (tag == ConstPool.CONST_Float)
+            stackTypes[stackTop++] = FLOAT;
+        else if (tag == ConstPool.CONST_Long) {
+            stackTypes[stackTop++] = LONG;
+            stackTypes[stackTop++] = TOP;
+        }
+        else if (tag == ConstPool.CONST_Double) {
+            stackTypes[stackTop++] = DOUBLE;
+            stackTypes[stackTop++] = TOP;
+        }
+        else if (tag == ConstPool.CONST_Class) {
+            stackTypes[stackTop] = OBJECT;
+            stackData[stackTop++] = "java/lang/Class";
+        }
+        else
+            throw new RuntimeException("bad LDC: " + tag);
+    }
+
+    private int doXLOAD(int type) {
+        int[] stackTypes = this.stackTypes;
+        stackTypes[stackTop++] = type;
+        if (type == LONG || type == DOUBLE)
+            stackTypes[stackTop++] = TOP;
+
+        return 2;
+    }
+
+    private String getDerefType(String type) throws BadBytecode {
+        if (type.charAt(0) == '[') {
+            String type2 = type.substring(1);
+            if (type2.length() > 0) {
+                char c = type2.charAt(0);
+                if (c == '[')
+                    return type2;
+                else if (c == 'L')
+                    return type2.substring(1, type.length() - 2);
+                else
+                    return type2;
+            }
+        }
+
+        throw new BadBytecode("bad array type for AALOAD: " + type);
+    }
+
+    private int doOpcode54_95(int pos, byte[] code, int op) {
+        int[] localsTypes = this.localsTypes;
+        int[] stackTypes = this.stackTypes;
+        switch (op) {
+        case Opcode.ISTORE :
+            return doXSTORE(pos, code, INTEGER);
+        case Opcode.LSTORE :
+            return doXSTORE(pos, code, LONG);
+        case Opcode.FSTORE :
+            return doXSTORE(pos, code, FLOAT);
+        case Opcode.DSTORE :
+            return doXSTORE(pos, code, DOUBLE);
+        case Opcode.ASTORE :
+            return doXSTORE(pos, code, OBJECT);
+        case Opcode.ISTORE_0 :
+        case Opcode.ISTORE_1 :
+        case Opcode.ISTORE_2 :
+        case Opcode.ISTORE_3 :
+          { int var = op - Opcode.ISTORE_0;
+            localsTypes[var] = INTEGER;
+            localsUpdated[var] = true; }
+            stackTop--;
+            break;
+        case Opcode.LSTORE_0 :
+        case Opcode.LSTORE_1 :
+        case Opcode.LSTORE_2 :
+        case Opcode.LSTORE_3 :
+          { int var = op - Opcode.LSTORE_0;
+            localsTypes[var] = LONG;
+            localsTypes[var + 1] = TOP;
+            localsUpdated[var] = true; }
+            stackTop -= 2;
+            break;
+        case Opcode.FSTORE_0 :
+        case Opcode.FSTORE_1 :
+        case Opcode.FSTORE_2 :
+        case Opcode.FSTORE_3 :
+          { int var = op - Opcode.FSTORE_0;
+            localsTypes[var] = FLOAT;
+            localsUpdated[var] = true; }
+            stackTop--;
+            break;
+        case Opcode.DSTORE_0 :
+        case Opcode.DSTORE_1 :
+        case Opcode.DSTORE_2 :
+        case Opcode.DSTORE_3 :
+          { int var = op - Opcode.DSTORE_0;
+            localsTypes[var] = DOUBLE;
+            localsTypes[var + 1] = TOP;
+            localsUpdated[var] = true; }
+            stackTop -= 2;
+            break;
+        case Opcode.ASTORE_0 :
+        case Opcode.ASTORE_1 :
+        case Opcode.ASTORE_2 :
+        case Opcode.ASTORE_3 :
+          { int var = op - Opcode.ASTORE_0;
+            localsTypes[var] = OBJECT;
+            localsUpdated[var] = true;
+            localsData[var] = stackData[--stackTop]; }
+            break;
+        case Opcode.IASTORE :
+        case Opcode.LASTORE :
+        case Opcode.FASTORE :
+        case Opcode.DASTORE :
+        case Opcode.AASTORE :
+        case Opcode.BASTORE :
+        case Opcode.CASTORE :
+        case Opcode.SASTORE :
+            stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
+            break;
+        case Opcode.POP :
+            stackTop--;
+            break;
+        case Opcode.POP2 :
+            stackTop -= 2;
+            break;
+        case Opcode.DUP : {
+            int sp = stackTop;
+            stackTypes[sp] = stackTypes[sp - 1];
+            stackData[sp] = stackData[sp - 1];
+            stackTop = sp + 1;
+            break; }
+        case Opcode.DUP_X1 :
+        case Opcode.DUP_X2 : {
+            int len = op - Opcode.DUP_X1 + 2;
+            doDUP_XX(1, len);
+            int sp = stackTop;
+            stackTypes[sp - len] = stackTypes[sp];
+            stackData[sp - len] = stackData[sp];
+            stackTop = sp + 1;
+            break; }
+        case Opcode.DUP2 :
+            doDUP_XX(2, 2);
+            stackTop += 2;
+            break;
+        case Opcode.DUP2_X1 :
+        case Opcode.DUP2_X2 : {
+            int len = op - Opcode.DUP2_X1 + 3;
+            doDUP_XX(2, len);
+            Object[] stackData = this.stackData;
+            int sp = stackTop;
+            stackTypes[sp - len] = stackTypes[sp];
+            stackData[sp - len] = stackData[sp];
+            stackTypes[sp - len + 1] = stackTypes[sp + 1];
+            stackData[sp - len + 1] = stackData[sp + 1];
+            stackTop = sp + 2; 
+            break; }
+        case Opcode.SWAP : {
+            Object[] stackData = this.stackData;
+            int sp = stackTop - 1;
+            int t = stackTypes[sp];
+            Object d = stackData[sp];
+            stackTypes[sp] = stackTypes[sp - 1];
+            stackData[sp] = stackData[sp - 1];
+            stackTypes[sp - 1] = t;
+            stackData[sp - 1] = d;
+            break; }
+        default :
+            throw new RuntimeException("fatal");
+        }
+
+        return 1;
+    }
+
+    private int doXSTORE(int pos, byte[] code, int type) {
+        int index = code[pos + 1] & 0xff;
+        return doXSTORE(index, type);
+    }
+
+    private int doXSTORE(int index, int type) {
+        stackTop--;
+        localsTypes[index] = type;
+        localsUpdated[index] = true;
+        if (type == LONG || type == DOUBLE) {
+            stackTop--;
+            localsTypes[index + 1] = TOP;
+        }
+        else if (type == OBJECT)
+            localsData[index] = stackData[stackTop];
+
+        return 2;
+    }
+
+    private void doDUP_XX(int delta, int len) {
+        int types[] = stackTypes;
+        Object data[] = stackData;
+        int sp = stackTop;
+        int end = sp - len;
+        while (sp > end) {
+            types[sp + delta] = types[sp];
+            data[sp + delta] = data[sp];
+            sp--;
+        }
+    }
+
+    private int doOpcode96_147(int pos, byte[] code, int op) {
+        if (op <= Opcode.LXOR) {    // IADD...LXOR
+            stackTop -= Opcode.STACK_GROW[op];
+            return 1;
+        }
+
+        switch (op) {
+        case Opcode.IINC :
+            return 3;
+        case Opcode.I2L :
+            stackTypes[stackTop] = LONG;
+            stackTypes[stackTop - 1] = TOP;
+            stackTop++;
+            break;
+        case Opcode.I2F :
+            stackTypes[stackTop - 1] = FLOAT;
+            break;
+        case Opcode.I2D :
+            stackTypes[stackTop] = DOUBLE;
+            stackTypes[stackTop - 1] = TOP;
+            stackTop++;
+            break;
+        case Opcode.L2I :
+            stackTypes[--stackTop - 1] = INTEGER;
+            break;
+        case Opcode.L2F :
+            stackTypes[--stackTop - 1] = FLOAT;
+            break;
+        case Opcode.L2D :
+            stackTypes[stackTop - 1] = DOUBLE;
+            break;
+        case Opcode.F2I :
+            stackTypes[stackTop - 1] = INTEGER;
+            break;
+        case Opcode.F2L :
+            stackTypes[stackTop - 1] = TOP;
+            stackTypes[stackTop++] = LONG;
+            break;
+        case Opcode.F2D :
+            stackTypes[stackTop - 1] = TOP;
+            stackTypes[stackTop++] = DOUBLE;
+            break;
+        case Opcode.D2I :
+            stackTypes[--stackTop - 1] = INTEGER;
+            break;
+        case Opcode.D2L :
+            stackTypes[stackTop - 1] = LONG;
+            break;
+        case Opcode.D2F :
+            stackTypes[--stackTop - 1] = FLOAT;
+            break;
+        case Opcode.I2B :
+        case Opcode.I2C :
+        case Opcode.I2S :
+            break;
+        default :
+            throw new RuntimeException("fatal");
+        }
+
+        return 1;
+    }
+
+    private int doOpcode148_201(int pos, byte[] code, int op) throws BadBytecode {
+        switch (op) {
+        case Opcode.LCMP :
+            stackTypes[stackTop - 4] = INTEGER;
+            stackTop -= 3;
+            break;
+        case Opcode.FCMPL :
+        case Opcode.FCMPG :
+            stackTypes[--stackTop - 1] = INTEGER;
+            break;
+        case Opcode.DCMPL :
+        case Opcode.DCMPG :
+            stackTypes[stackTop - 4] = INTEGER;
+            stackTop -= 3;
+            break;
+        case Opcode.IFEQ :
+        case Opcode.IFNE :
+        case Opcode.IFLT :
+        case Opcode.IFGE :
+        case Opcode.IFGT :
+        case Opcode.IFLE :
+            stackTop--;     // branch
+            visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
+            return 3;
+        case Opcode.IF_ICMPEQ :
+        case Opcode.IF_ICMPNE :
+        case Opcode.IF_ICMPLT :
+        case Opcode.IF_ICMPGE :
+        case Opcode.IF_ICMPGT :
+        case Opcode.IF_ICMPLE :
+        case Opcode.IF_ACMPEQ :
+        case Opcode.IF_ACMPNE :
+            stackTop -= 2;  // branch
+            visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
+            return 3;
+        case Opcode.GOTO :
+            visitGoto(pos, code, ByteArray.readS16bit(code, pos + 1));
+            return 3;       // branch
+        case Opcode.JSR :
+            stackTypes[stackTop++] = TOP;       // not allowed?
+            visitJSR(pos, code);
+            return 3;       // branch
+        case Opcode.RET :
+            visitRET(pos, code);
+            return 2;                           // not allowed?
+        case Opcode.TABLESWITCH : {
+            stackTop--;     // branch
+            int pos2 = (pos & ~3) + 8;
+            int low = ByteArray.read32bit(code, pos2);
+            int high = ByteArray.read32bit(code, pos2 + 4);
+            int n = high - low + 1;
+            visitTableSwitch(pos, code, n, pos2 + 8, ByteArray.read32bit(code, pos2 - 4));
+            return n * 4 + 16 - (pos & 3); }
+        case Opcode.LOOKUPSWITCH : {
+            stackTop--;     // branch
+            int pos2 = (pos & ~3) + 8;
+            int n = ByteArray.read32bit(code, pos2);
+            visitLookupSwitch(pos, code, n, pos2 + 4, ByteArray.read32bit(code, pos2 - 4));
+            return n * 8 + 12 - (pos & 3); }
+        case Opcode.IRETURN :
+            stackTop--;
+            visitReturn(pos, code);
+            break;
+        case Opcode.LRETURN :
+            stackTop -= 2;
+            visitReturn(pos, code);
+            break;
+        case Opcode.FRETURN :
+            stackTop--;
+            visitReturn(pos, code);
+            break;
+        case Opcode.DRETURN :
+            stackTop -= 2;
+            visitReturn(pos, code);
+            break;
+        case Opcode.ARETURN :
+            stackTop--;
+            visitReturn(pos, code);
+            break;
+        case Opcode.RETURN :
+            visitReturn(pos, code);
+            break;
+        case Opcode.GETSTATIC :
+            return doFieldAccess(pos, code, true);
+        case Opcode.PUTSTATIC :
+            return doFieldAccess(pos, code, false);
+        case Opcode.GETFIELD :
+            stackTop--;
+            return doFieldAccess(pos, code, true);
+        case Opcode.PUTFIELD :
+            stackTop--;
+            return doFieldAccess(pos, code, false);
+        case Opcode.INVOKEVIRTUAL :
+        case Opcode.INVOKESPECIAL :
+            return doInvokeMethod(pos, code, 1);
+        case Opcode.INVOKESTATIC :
+            return doInvokeMethod(pos, code, 0);
+        case Opcode.INVOKEINTERFACE :
+            return doInvokeIntfMethod(pos, code, 1);
+        case 186 :
+            throw new RuntimeException("bad opcode 186");
+        case Opcode.NEW : {
+            int i = ByteArray.readU16bit(code, pos + 1);
+            stackTypes[stackTop - 1] = UNINIT;
+            stackData[stackTop - 1] = new Integer(pos);
+            return 3; }
+        case Opcode.NEWARRAY :
+            return doNEWARRAY(pos, code);
+        case Opcode.ANEWARRAY : {
+            int i = ByteArray.readU16bit(code, pos + 1);
+            stackTypes[stackTop - 1] = OBJECT;
+            stackData[stackTop - 1]
+                      = "[L" + cpool.getClassInfo(i).replace('.', '/') + ";";
+            return 3; }
+        case Opcode.ARRAYLENGTH :
+            stackTypes[stackTop - 1] = INTEGER;
+            break;
+        case Opcode.ATHROW :
+            stackTop--;         // branch?
+            visitThrow(pos, code);
+            break;
+        case Opcode.CHECKCAST : {
+            int i = ByteArray.readU16bit(code, pos + 1);
+            stackData[stackTop - 1] = cpool.getClassInfo(i);
+            return 3; }
+        case Opcode.INSTANCEOF :
+            stackTypes[stackTop - 1] = INTEGER;
+            return 3;
+        case Opcode.MONITORENTER :
+        case Opcode.MONITOREXIT :
+            stackTop--;
+            break;
+        case Opcode.WIDE :
+            return doWIDE(pos, code);
+        case Opcode.MULTIANEWARRAY :
+            return doMultiANewArray(pos, code);
+        case Opcode.IFNULL :
+        case Opcode.IFNONNULL :
+            stackTop--;         // branch
+            visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
+            return 3;
+        case Opcode.GOTO_W :
+            visitGoto(pos, code, ByteArray.read32bit(code, pos + 1));
+            return 5;           // branch
+        case Opcode.JSR_W :
+            stackTypes[stackTop++] = TOP;       // not allowed?
+            visitJSR(pos, code);
+            return 5;
+        }
+        return 1;
+    }
+
+    private int doWIDE(int pos, byte[] code) {
+        int op = code[pos + 1] & 0xff;
+        switch (op) {
+        case Opcode.ILOAD :
+            doXLOAD(INTEGER);
+            break;
+        case Opcode.LLOAD :
+            doXLOAD(LONG);
+            break;
+        case Opcode.FLOAD :
+            doXLOAD(FLOAT);
+            break;
+        case Opcode.DLOAD :
+            doXLOAD(DOUBLE);
+            break;
+        case Opcode.ALOAD :
+            stackTypes[stackTop] = OBJECT;
+            stackData[stackTop++] = localsData[ByteArray.readU16bit(code, pos)];
+            break;
+        case Opcode.ISTORE :
+            return doWIDE_STORE(pos, code, INTEGER);
+        case Opcode.LSTORE :
+            return doWIDE_STORE(pos, code, LONG);
+        case Opcode.FSTORE :
+            return doWIDE_STORE(pos, code, FLOAT);
+        case Opcode.DSTORE :
+            return doWIDE_STORE(pos, code, DOUBLE);
+        case Opcode.ASTORE :
+            return doWIDE_STORE(pos, code, OBJECT);
+        case Opcode.IINC :
+            return 6;
+        case Opcode.RET :
+            break;
+        default :
+            throw new RuntimeException("bad WIDE instruction: " + op);
+        }
+
+        return 4;
+    }
+
+    private int doWIDE_STORE(int pos, byte[] code, int type) {
+        int index = ByteArray.readU16bit(code, pos);
+        return doXSTORE(index, type);
+    }
+
+    private int doFieldAccess(int pos, byte[] code, boolean isGet) {
+        int index = ByteArray.readU16bit(code, pos + 1);
+        String desc = cpool.getFieldrefType(index);
+        if (isGet)
+            pushMemberType(desc);
+        else
+            stackTop -= Descriptor.dataSize(desc);
+
+        return 3;
+    }
+
+    private int doNEWARRAY(int pos, byte[] code) {
+        int s = stackTop - 1;
+        stackTypes[s] = OBJECT;
+        String type;
+        switch (code[pos + 1] & 0xff) {
+        case Opcode.T_BOOLEAN :
+            type = "[Z";
+            break;
+        case Opcode.T_CHAR :
+            type = "[C";
+            break;
+        case Opcode.T_FLOAT :
+            type = "[F";
+            break;
+        case Opcode.T_DOUBLE :
+            type = "[D";
+            break;
+        case Opcode.T_BYTE :
+            type = "[B";
+            break;
+        case Opcode.T_SHORT :
+            type = "[S";
+            break;
+        case Opcode.T_INT :
+            type = "[I";
+            break;
+        case Opcode.T_LONG :
+            type = "[J";
+            break;
+        default :
+            throw new RuntimeException("bad newarray");
+        }
+
+        stackData[s] = type;
+        return 2;
+    }
+
+    private int doMultiANewArray(int pos, byte[] code) {
+        int i = ByteArray.readU16bit(code, pos + 1);
+        int dim = code[pos + 3] & 0xff;
+        stackTop -= dim - 1;
+        String type = cpool.getClassInfo(i);
+        StringBuffer sbuf = new StringBuffer();
+        while (dim-- > 0)
+            sbuf.append('[');
+
+        sbuf.append('L').append(type.replace('.', '/')).append(';');
+        stackTypes[stackTop - 1] = OBJECT;
+        stackData[stackTop - 1] = sbuf.toString(); 
+        return 4;
+    }
+
+    private int doInvokeMethod(int pos, byte[] code, int targetSize) {
+        int i = ByteArray.readU16bit(code, pos + 1);
+        String desc = cpool.getMethodrefType(i);
+        stackTop -= Descriptor.paramSize(desc) + targetSize;
+        pushMemberType(desc);
+        return 3;
+    }
+
+    private int doInvokeIntfMethod(int pos, byte[] code, int targetSize) {
+        int i = ByteArray.readU16bit(code, pos + 1);
+        String desc = cpool.getInterfaceMethodrefType(i);
+        stackTop -= Descriptor.paramSize(desc) + targetSize;
+        pushMemberType(desc);
+        return 5;
+    }
+
+    private void pushMemberType(String descriptor) {
+        int top = 0;
+        if (descriptor.charAt(0) == '(') {
+            top = descriptor.indexOf(')') + 1;
+            if (top < 1)
+                throw new IndexOutOfBoundsException("bad descriptor: "
+                                                    + descriptor);
+        }
+
+        int[] types = stackTypes;
+        int index = stackTop;
+        switch (descriptor.charAt(top)) {
+        case '[' :
+            types[index] = OBJECT;
+            stackData[index] = descriptor.substring(top);
+            break;
+        case 'L' :
+            types[index] = OBJECT;
+            stackData[index] = descriptor.substring(top + 1,
+                                        descriptor.indexOf(';', top));
+            break;
+        case 'J' :
+            types[index] = LONG;
+            types[index + 1] = TOP;
+            stackTop += 2;
+            return;
+        case 'F' :
+            types[index] = FLOAT;
+            break;
+        case 'D' :
+            types[index] = DOUBLE;
+            types[index + 1] = TOP;
+            stackTop += 2;
+            return;
+        case 'V' :
+            return;
+        default : // C, B, S, I, Z
+            types[index] = INTEGER;
+            break;
+        }
+
+        stackTop++;
+    }
+}
index 9b08a128125c07751e4b57a1c65c2df27897986a..afa944b6d9ea503ed07cdd95639fed65d4967170 100644 (file)
@@ -14,7 +14,6 @@
  */
 package javassist.convert;
 
-
 import javassist.CtClass;
 import javassist.NotFoundException;
 import javassist.CodeConverter.ArrayAccessReplacementMethodNames;
@@ -25,43 +24,44 @@ import javassist.bytecode.ConstPool;
 /**
  *  
  * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
- * @version $Revision: 1.2 $ 
+ * @version $Revision: 1.3 $ 
  */
-public class TransformAccessArrayField extends Transformer 
-{
-//   CtClass componentType;
+public class TransformAccessArrayField extends Transformer {
+// CtClass componentType;
 
    String methodClassname;
    ArrayAccessReplacementMethodNames names;
 
-   public TransformAccessArrayField(Transformer next, String methodClassname, ArrayAccessReplacementMethodNames names) throws NotFoundException
+   public TransformAccessArrayField(Transformer next, String methodClassname,
+                                    ArrayAccessReplacementMethodNames names)
+       throws NotFoundException
    {
        super(next);
        this.methodClassname = methodClassname;
        this.names = names;
    }
 
-   public int transform(CtClass tclazz, int pos, CodeIterator iterator, ConstPool cp) throws BadBytecode
+   public int transform(CtClass tclazz, int pos, CodeIterator iterator,
+                        ConstPool cp) throws BadBytecode
    {
       int c = iterator.byteAt(pos);
       
-      if (c == AALOAD || c == BALOAD || c == CALOAD || c == DALOAD || c == FALOAD || c == IALOAD || c == LALOAD || c == SALOAD) 
-      {
+      if (c == AALOAD || c == BALOAD || c == CALOAD || c == DALOAD
+          || c == FALOAD || c == IALOAD || c == LALOAD || c == SALOAD)
          replace(cp, iterator, pos, c, getLoadReplacementSignature(c));
-      }
-      else if (c == AASTORE || c == BASTORE || c == CASTORE || c == DASTORE || c == FASTORE || c == IASTORE || c == LASTORE || c == SASTORE)
-      {
+      else if (c == AASTORE || c == BASTORE || c == CASTORE || c == DASTORE
+               || c == FASTORE || c == IASTORE || c == LASTORE || c == SASTORE)
          replace(cp, iterator, pos, c, getStoreReplacementSignature(c));
-      }
 
       return pos;
    }
    
-   private void replace(ConstPool cp, CodeIterator iterator, int pos, int opcode, String signature) throws BadBytecode
+   private void replace(ConstPool cp, CodeIterator iterator,
+                        int pos, int opcode, String signature)
+       throws BadBytecode
    {
       String methodName = getMethodName(opcode);
-      if (methodName != null)
-      {
+      if (methodName != null) {
          iterator.insertGap(2);
          int mi = cp.addClassInfo(methodClassname);
          int methodref = cp.addMethodrefInfo(mi, methodName, signature);
@@ -70,114 +70,112 @@ public class TransformAccessArrayField extends Transformer
       }
    }
 
-   private String getMethodName(int opcode)
-   {
-      String methodName = null;
-      switch(opcode)
-      {
-         case AALOAD:
+   private String getMethodName(int opcode) {
+        String methodName = null;
+        switch (opcode) {
+        case AALOAD:
             methodName = names.objectRead();
             break;
-         case BALOAD:
+        case BALOAD:
             methodName = names.byteOrBooleanRead();
             break;
-         case CALOAD:
+        case CALOAD:
             methodName = names.charRead();
             break;
-         case DALOAD:
+        case DALOAD:
             methodName = names.doubleRead();
             break;
-         case FALOAD:
+        case FALOAD:
             methodName = names.floatRead();
             break;
-         case IALOAD:
+        case IALOAD:
             methodName = names.intRead();
             break;
-         case SALOAD:
+        case SALOAD:
             methodName = names.shortRead();
             break;
-         case LALOAD:
+        case LALOAD:
             methodName = names.longRead();
             break;
-         case AASTORE:
+        case AASTORE:
             methodName = names.objectWrite();
             break;
-         case BASTORE:
+        case BASTORE:
             methodName = names.byteOrBooleanWrite();
             break;
-         case CASTORE:
+        case CASTORE:
             methodName = names.charWrite();
             break;
-         case DASTORE:
+        case DASTORE:
             methodName = names.doubleWrite();
             break;
-         case FASTORE:
+        case FASTORE:
             methodName = names.floatWrite();
             break;
-         case IASTORE:
+        case IASTORE:
             methodName = names.intWrite();
             break;
-         case SASTORE:
+        case SASTORE:
             methodName = names.shortWrite();
             break;
-         case LASTORE:
+        case LASTORE:
             methodName = names.longWrite();
             break;
-      }
-      
-      if (methodName.equals(""))
-      {
-         methodName = null;
-      }
-      return methodName;
-   }
+        }
 
-   private String getLoadReplacementSignature(int opcode) throws BadBytecode
+        if (methodName.equals(""))
+            methodName = null;
+
+        return methodName;
+    }
+
+   private String getLoadReplacementSignature(int opcode)
+       throws BadBytecode
    {
-      switch(opcode) 
-      {
-         case AALOAD:
+        switch (opcode) {
+        case AALOAD:
             return "(Ljava/lang/Object;I)Ljava/lang/Object;";
-         case BALOAD:
+        case BALOAD:
             return "(Ljava/lang/Object;I)B";
-         case CALOAD:
+        case CALOAD:
             return "(Ljava/lang/Object;I)C";
-         case DALOAD:
+        case DALOAD:
             return "(Ljava/lang/Object;I)D";
-         case FALOAD:
+        case FALOAD:
             return "(Ljava/lang/Object;I)F";
-         case IALOAD:
+        case IALOAD:
             return "(Ljava/lang/Object;I)I";
-         case SALOAD:
+        case SALOAD:
             return "(Ljava/lang/Object;I)S";
-         case LALOAD:
+        case LALOAD:
             return "(Ljava/lang/Object;I)J";
-      }      
-      
-      throw new BadBytecode(opcode);
-   }
+        }
+
+        throw new BadBytecode(opcode);
+    }
    
-   private String getStoreReplacementSignature(int opcode) throws BadBytecode
+   private String getStoreReplacementSignature(int opcode)
+       throws BadBytecode
    {
-      switch(opcode) 
-      {
-         case AASTORE:
+        switch (opcode) {
+        case AASTORE:
             return "(Ljava/lang/Object;ILjava/lang/Object;)V";
-         case BASTORE:
+        case BASTORE:
             return "(Ljava/lang/Object;IB)V";
-         case CASTORE:
+        case CASTORE:
             return "(Ljava/lang/Object;IC)V";
-         case DASTORE:
+        case DASTORE:
             return "(Ljava/lang/Object;ID)V";
-         case FASTORE:
+        case FASTORE:
             return "(Ljava/lang/Object;IF)V";
-         case IASTORE:
+        case IASTORE:
             return "(Ljava/lang/Object;II)V";
-         case SASTORE:
+        case SASTORE:
             return "(Ljava/lang/Object;IS)V";
-         case LASTORE:
+        case LASTORE:
             return "(Ljava/lang/Object;IJ)V";
-      }      
-      throw new BadBytecode(opcode);
-   }
+        }
+
+        throw new BadBytecode(opcode);
+    }
 }
index c4347b7c05befe11cca45a3397090e579daa0e32..a853d2d58e931cecb14af76d8cbdf5fc323b8000 100644 (file)
@@ -64,6 +64,11 @@ final public class TransformNew extends Transformer {
                 iterator.writeByte(NOP, pos + 2);
                 iterator.writeByte(NOP, pos + 3);
                 ++nested;
+
+                StackMapTable smt
+                    = (StackMapTable)iterator.get().getAttribute(StackMapTable.tag);
+                if (smt != null)
+                    smt.removeNew(pos);
             }
         }
         else if (c == INVOKESPECIAL) {
diff --git a/src/test/test/Test.java b/src/test/test/Test.java
new file mode 100644 (file)
index 0000000..29a08a6
--- /dev/null
@@ -0,0 +1,14 @@
+package test;
+
+import javassist.bytecode.*;
+
+public class Test {
+    public static void main(String[] args) {
+        String[] names = Mnemonic.OPCODE;
+        for (int i = 0; i < names.length; i++)
+            if (names[i] == null)
+                System.out.println("        case " + i + " :");
+            else
+                System.out.println("        case Opcode." + names[i].toUpperCase() + " :");
+    }
+}