[jboss-cvs] javassist/src/main/javassist/bytecode/stackmap ...

Shigeru Chiba chiba at is.titech.ac.jp
Sun May 6 11:41:43 EDT 2007


  User: chiba   
  Date: 07/05/06 11:41:43

  Modified:    src/main/javassist/bytecode/stackmap       BasicBlock.java
                        MapMaker.java TypeData.java Tracer.java
  Added:       src/main/javassist/bytecode/stackmap       TypedBlock.java
                        Liveness.java
  Log:
  implemented javassist.bytecode.stackmap package.
  
  Revision  Changes    Path
  1.5       +311 -362  javassist/src/main/javassist/bytecode/stackmap/BasicBlock.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: BasicBlock.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/BasicBlock.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -b -r1.4 -r1.5
  --- BasicBlock.java	26 Apr 2007 14:58:16 -0000	1.4
  +++ BasicBlock.java	6 May 2007 15:41:43 -0000	1.5
  @@ -16,183 +16,196 @@
   package javassist.bytecode.stackmap;
   
   import javassist.bytecode.*;
  +import java.util.HashMap;
   import java.util.ArrayList;
   
  -public class BasicBlock implements TypeTag, Comparable {
  -
  +public class BasicBlock {
       public int position, length;
  -    public int stackTop, numLocals;
  -    public TypeData[] stackTypes, localsTypes;
  +    public int incoming;        // the number of incoming branches.
  +    public BasicBlock[] exit;   // null if the block is a leaf.
  +    public boolean stop;        // true if the block ends with an unconditional jump. 
  +    public Catch toCatch;
   
  -    /* The version number of the values of numLocals and localsTypes.
  -     * These values are repeatedly updated while MapMaker#make()
  -     * is running.  This field represents when the values are recorded.
  -     */
  -    public int version;
  +    protected BasicBlock(int pos) {
  +        position = pos;
  +        length = 0;
  +        incoming = 0;
  +    }
   
  -    /* a flag used by MapMaker#recordUsage()
  -     */
  -    public int[] localsUsage;
  +    public static BasicBlock find(BasicBlock[] blocks, int pos)
  +        throws BadBytecode
  +    {
  +        for (int i = 0; i < blocks.length; i++) {
  +            int iPos = blocks[i].position;
  +            if (iPos <= pos && pos < iPos + blocks[i].length)
  +                return blocks[i];
  +        }
   
  -    /* The number of the basic blocks from which a thread of control
  -     * may reach this basic block.  The number excludes the preceding
  -     * block.  Thus, if it is zero, a thread of control reaches
  -     * only from the preceding block.  Such a basic block represents
  -     * the boundary of a try block.
  -     */
  -    public int inbound;
  +        throw new BadBytecode("no basic block at " + pos);
  +    }
   
  -    public static class Branch {
  -        public Branch next;
  -        public int target;
  -        public int typeIndex;   // exception type
  -        public Branch(Branch next, int target, int type) {
  -            this.next = next;
  -            this.target = target;
  -            this.typeIndex = type;
  +    public static class Catch {
  +        Catch next;
  +        BasicBlock body;
  +        int typeIndex;
  +        Catch(BasicBlock b, int i, Catch c) {
  +            body = b;
  +            typeIndex = i;
  +            next = c;
           }
       }
   
  -    /* A list of catch clauses that a thread may jump
  -     * from this block to.
  -     */
  -    public Branch catchBlocks;
  +    public String toString() {
  +        StringBuffer sbuf = new StringBuffer();
  +        String cname = this.getClass().getName();
  +        int i = cname.lastIndexOf('.');
  +        sbuf.append(i < 0 ? cname : cname.substring(i + 1));
  +        sbuf.append("[");
  +        toString2(sbuf);
  +        sbuf.append("]");
  +        return sbuf.toString();
  +    }
   
  -    /* public static void main(String[] args) throws Exception {
  -        BasicBlock b = new BasicBlock(0);
  -        b.initFirstBlock(8, 1, args[0], args[1], args[2].equals("static"), args[2].equals("const"));
  -        System.out.println(b);
  -    }*/
  +    protected void toString2(StringBuffer sbuf) {
  +        sbuf.append("pos=").append(position).append(", len=")
  +            .append(length).append(", in=").append(incoming)
  +            .append(", exit{");
  +        if (exit != null) {
  +            for (int i = 0; i < exit.length; i++)
  +                sbuf.append(exit[i].position).append(", ");
  +        }
  +
  +        sbuf.append("}, {");
  +        Catch th = toCatch;
  +        while (th != null) {
  +            sbuf.append("(").append(th.body.position).append(", ")
  +                .append(th.typeIndex).append("), ");
  +            th = th.next;
  +        }
  +
  +        sbuf.append("}");
  +    }
  +
  +    static class Mark implements Comparable {
  +        int position;
  +        BasicBlock block;
  +        BasicBlock[] jump;
  +        boolean alwaysJmp;     // true if a unconditional branch.
  +        int size;       // 0 unless the mark indicates RETURN etc. 
  +        Catch catcher;
  +
  +        Mark(int p) {
  +            position = p;
  +            block = null;
  +            jump = null;
  +            alwaysJmp = false;
  +            size = 0;
  +            catcher = null;
  +        }
   
  -    private BasicBlock(int pos) {
  -        position = pos;
  -        length = 0;
  -        stackTop = numLocals = 0;
  -        stackTypes = localsTypes = null;
  -        inbound = 1;
  -        localsUsage = null;
  -        catchBlocks = null;
  +        public int compareTo(Object obj) {
  +            if (obj instanceof Mark) {
  +                int pos = ((Mark)obj).position;
  +                return position - pos;
  +            }
  +
  +            return -1;
       }
   
  -    public boolean alreadySet(int ver) {
  -        return stackTypes != null && ver == version;
  +        void setJump(BasicBlock[] bb, int s, boolean always) {
  +            jump = bb;
  +            size = s;
  +            alwaysJmp = always;
  +        }
       }
   
  -    /*
  -     * Computes the correct value of numLocals.
  -     * It assumes that:
  -     *     correct numLocals <= current numLocals 
  +    public static class Maker {
  +        /* Override these two methods if a subclass of BasicBlock must be
  +         * instantiated.
        */
  -    public void resetNumLocals() {
  -        if (localsTypes != null) {
  -            int nl = numLocals;
  -            while (nl > 0 && localsTypes[nl - 1] == TypeTag.TOP) {
  -                if (nl > 1) {
  -                    TypeData td = localsTypes[nl - 2];
  -                    if (td == TypeTag.LONG || td == TypeTag.DOUBLE)
  -                        break;
  +        protected BasicBlock makeBlock(int pos) {
  +            return new BasicBlock(pos);
  +        }
  +
  +        protected BasicBlock[] makeArray(int size) {
  +            return new BasicBlock[size];
                   }
   
  -                --nl;
  +        private BasicBlock[] makeArray(BasicBlock b) {
  +            BasicBlock[] array = makeArray(1);
  +            array[0] = b;
  +            return array;
               }
   
  -            numLocals = nl;
  +        private BasicBlock[] makeArray(BasicBlock b1, BasicBlock b2) {
  +            BasicBlock[] array = makeArray(2);
  +            array[0] = b1;
  +            array[1] = b2;
  +            return array;
           }
  +
  +        public BasicBlock[] make(MethodInfo minfo) throws BadBytecode {
  +            CodeAttribute ca = minfo.getCodeAttribute();
  +            if (ca == null)
  +                return null;
  +
  +            CodeIterator ci = ca.iterator();
  +            return make(ci, 0, ci.getCodeLength(), ca.getExceptionTable());
       }
   
  -    public void setStackMap(int st, TypeData[] stack,
  -                            int nl, TypeData[] locals)
  +        public BasicBlock[] make(CodeIterator ci, int begin, int end,
  +                                 ExceptionTable et)
           throws BadBytecode
       {
  -        stackTop = st;
  -        stackTypes = stack;
  -        numLocals = nl;
  -        localsTypes = locals;
  +            HashMap marks = makeMarks(ci, begin, end, et);
  +            BasicBlock[] bb = makeBlocks(marks);
  +            addCatchers(bb, et);
  +            return bb;
       }
   
  -    private void updateLength(int nextPos) {
  -        length = nextPos - position;
  +        /* Branch target
  +         */
  +        private Mark makeMark(HashMap table, int pos) {
  +            return makeMark0(table, pos, true, true);
       }
   
  -    public String toString() {
  -        StringBuffer sbuf = new StringBuffer();
  -        sbuf.append("Block at ");
  -        sbuf.append(position);
  -        sbuf.append(" stack={");
  -        printTypes(sbuf, stackTop, stackTypes);
  -        sbuf.append("} locals={");
  -        printTypes(sbuf, numLocals, localsTypes);
  -        sbuf.append('}');
  -        return sbuf.toString();
  +        /* Branch instruction.
  +         * size > 0
  +         */
  +        private Mark makeMark(HashMap table, int pos, BasicBlock[] jump,
  +                              int size, boolean always) {
  +            Mark m = makeMark0(table, pos, false, false);
  +            m.setJump(jump, size, always);
  +            return m;
       }
   
  -    private static void printTypes(StringBuffer sbuf, int size,
  -                                   TypeData[] types) {
  -        if (types == null)
  -            return;
  -
  -        for (int i = 0; i < size; i++) {
  -            if (i > 0)
  -                sbuf.append(", ");
  -
  -            TypeData td = types[i];
  -            sbuf.append(td == null ? "<>" : td.toString());
  -        }
  +        private Mark makeMark0(HashMap table, int pos,
  +                               boolean isBlockBegin, boolean isTarget) {
  +            Integer p = new Integer(pos);
  +            Mark m = (Mark)table.get(p);
  +            if (m == null) {
  +                m = new Mark(pos);
  +                table.put(p, m);
       }
   
  -    /**
  -     * Finds the basic block including the given position.
  -     *
  -     * @param pos       the position.
  -     */
  -    public static BasicBlock find(BasicBlock[] blocks, int pos) throws BadBytecode {
  -        int n = blocks.length;
  -        for (int i = 0; i < n; i++)
  -            if (blocks[i].position == pos)
  -                return blocks[i];
  +            if (isBlockBegin) {
  +                if (m.block == null)
  +                    m.block = makeBlock(pos);
   
  -        throw new BadBytecode("no basic block: " + pos);
  +                if (isTarget)
  +                    m.block.incoming++;
       }
   
  -    /**
  -     * Divides the given code fragment into basic blocks.
  -     * It returns null if the given MethodInfo does not include
  -     * a CodeAttribute.
  -     */
  -    public static BasicBlock[] makeBlocks(MethodInfo minfo) throws BadBytecode {
  -        CodeAttribute ca = minfo.getCodeAttribute();
  -        if (ca == null)
  -            return null;
  +            return m;
  +        }
   
  -        CodeIterator ci = ca.iterator();
  -        ConstPool pool = minfo.getConstPool();
  -        BasicBlock[] blocks = makeBlocks(ci, 0, ci.getCodeLength(), ca.getExceptionTable(), 0, pool);
  -        boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
  -        blocks[0].initFirstBlock(ca.getMaxStack(), ca.getMaxLocals(),
  -                                 pool.getClassName(), minfo.getDescriptor(),
  -                                 isStatic, minfo.isConstructor());
  -        return blocks;
  -    }
  -
  -    /**
  -     * Divides the given code fragment into basic blocks.
  -     *
  -     * @param begin         the position where the basic block analysis starts. 
  -     * @param end           exclusive.
  -     * @param et            the appended exception table entries.
  -     * @param etOffset      the offset added to the handlerPc entries in the exception table.
  -     * @param pool          the constant pool.
  -     */
  -    public static BasicBlock[] makeBlocks(CodeIterator ci, int begin, int end,
  -                                           ExceptionTable et, int etOffset, ConstPool pool)
  +        private HashMap makeMarks(CodeIterator ci, int begin, int end,
  +                                  ExceptionTable et)
           throws BadBytecode
       {
           ci.begin();
           ci.move(begin);
  -        ArrayList targets = new ArrayList();
  -        BasicBlock bb0 = new BasicBlock(begin);
  -        bb0.inbound = 0;    // the first block is not a branch target.
  -        targets.add(bb0);
  +            HashMap marks = new HashMap();
           while (ci.hasNext()) {
               int index = ci.next();
               if (index >= end)
  @@ -200,237 +213,173 @@
   
               int op = ci.byteAt(index);
               if ((Opcode.IFEQ <= op && op <= Opcode.IF_ACMPNE)
  -                || op == Opcode.IFNULL || op == Opcode.IFNONNULL)
  -                targets.add(new BasicBlock(index + ci.s16bitAt(index + 1)));
  +                        || op == Opcode.IFNULL || op == Opcode.IFNONNULL) {
  +                    Mark to = makeMark(marks, index + ci.s16bitAt(index + 1));
  +                    Mark next = makeMark(marks, index + 3);
  +                    makeMark(marks, index, makeArray(to.block, next.block), 3, false);
  +                }
               else if (Opcode.GOTO <= op && op <= Opcode.LOOKUPSWITCH)
                   switch (op) {
                   case Opcode.GOTO :
                   case Opcode.JSR :
  -                    targets.add(new BasicBlock(index + ci.s16bitAt(index + 1)));
  +                        makeGotoJsr(marks, index, index + ci.s16bitAt(index + 1),
  +                                    op == Opcode.GOTO, 3);
  +                        break;
  +                    case Opcode.RET :
  +                        makeMark(marks, index, null, 1, true);
                       break;
  -                // case Opcode.RET :
  -                //    throw new BadBytecode("ret at " + index);
                   case Opcode.TABLESWITCH : {
                       int pos = (index & ~3) + 4;
  -                    targets.add(new BasicBlock(index + ci.s32bitAt(pos)));   // default branch target
                       int low = ci.s32bitAt(pos + 4);
                       int high = ci.s32bitAt(pos + 8);
  +                        int ncases = high - low + 1;
  +                        BasicBlock[] to = makeArray(ncases + 1);
  +                        to[0] = makeMark(marks, index + ci.s32bitAt(pos)).block;   // default branch target
                       int p = pos + 12;
  -                    int n = p + (high - low + 1) * 4;
  +                        int n = p + ncases * 4;
  +                        int k = 1;
                       while (p < n) {
  -                        targets.add(new BasicBlock(index + ci.s32bitAt(p)));
  +                            to[k++] = makeMark(marks, index + ci.s32bitAt(p)).block;
                           p += 4;
                       }
  +                        makeMark(marks, index, to, n - index, true);
                       break; }
                   case Opcode.LOOKUPSWITCH : {
                       int pos = (index & ~3) + 4;
  -                    targets.add(new BasicBlock(index + ci.s32bitAt(pos)));   // default branch target
  +                        int ncases = ci.s32bitAt(pos + 4);
  +                        BasicBlock[] to = makeArray(ncases + 1);
  +                        to[0] = makeMark(marks, index + ci.s32bitAt(pos)).block;   // default branch target
                       int p = pos + 8 + 4;
  -                    int n = p + ci.s32bitAt(pos + 4) * 8;
  +                        int n = p + ncases * 8 - 4;
  +                        int k = 1;
                       while (p < n) {
  -                        targets.add(new BasicBlock(index + ci.s32bitAt(p)));
  +                            to[k++] = makeMark(marks, index + ci.s32bitAt(p)).block;
                           p += 8;
                       }
  +                        makeMark(marks, index, to, n - index, true);
                       break; }
                   }
  +                else if ((Opcode.IRETURN <= op && op <= Opcode.RETURN) || op == Opcode.ATHROW)
  +                    makeMark(marks, index, null, 1, true);
               else if (op == Opcode.GOTO_W || op == Opcode.JSR_W)
  -                targets.add(new BasicBlock(index + ci.s32bitAt(index + 1)));
  +                    makeGotoJsr(marks, index, index + ci.s32bitAt(index + 1),
  +                                op == Opcode.GOTO_W, 5);
  +                else if (op == Opcode.WIDE && ci.byteAt(index + 1) == Opcode.RET)
  +                    makeMark(marks, index, null, 1, true);
           }
   
           if (et != null) {
               int i = et.size();
               while (--i >= 0) {
  -                BasicBlock bb = new BasicBlock(et.startPc(i) + etOffset);
  -                bb.inbound = 0;
  -                targets.add(bb);
  -                targets.add(new BasicBlock(et.handlerPc(i) + etOffset));
  +                    makeMark0(marks, et.startPc(i), true, false);
  +                    makeMark(marks, et.handlerPc(i));
               }
           }
   
  -        BasicBlock[] blocks = trimArray(targets, end);
  -        markCatch(et, etOffset, blocks);
  -        return blocks;
  +            return marks;
       }
   
  -    public int compareTo(Object obj) {
  -        if (obj instanceof BasicBlock) {
  -            int pos = ((BasicBlock)obj).position;
  -            return position - pos;
  +        private void makeGotoJsr(HashMap marks, int pos, int target, boolean isGoto, int size) {
  +            Mark to = makeMark(marks, target);
  +            BasicBlock[] jumps;
  +            if (isGoto)
  +                jumps = makeArray(to.block);
  +            else {
  +                Mark next = makeMark(marks, pos + size);
  +                jumps = makeArray(to.block, next.block);
           }
   
  -        return -1;
  +            makeMark(marks, pos, jumps, size, isGoto);
       }
   
  -    /**
  -     * @param endPos        exclusive
  -     */
  -    private static BasicBlock[] trimArray(ArrayList targets, int endPos) {
  -        Object[] targetArray = targets.toArray();
  -        int size = targetArray.length;
  -        java.util.Arrays.sort(targetArray);
  -        int s = 0;
  -        int t0 = -1;
  -        for (int i = 0; i < size; i++) {
  -            int t = ((BasicBlock)targetArray[i]).position;
  -            if (t != t0) {
  -                s++;
  -                t0 = t;
  +        private BasicBlock[] makeBlocks(HashMap markTable) {
  +            Mark[] marks = (Mark[])markTable.values()
  +                                            .toArray(new Mark[markTable.size()]);
  +            java.util.Arrays.sort(marks);
  +            ArrayList blocks = new ArrayList();
  +            int i = 0;
  +            BasicBlock prev;
  +            if (marks.length > 0 && marks[0].position == 0 && marks[0].block != null)
  +                prev = getBBlock(marks[i++]);
  +            else
  +                prev = makeBlock(0);
  +
  +            blocks.add(prev);
  +            while (i < marks.length) {
  +                Mark m = marks[i++];
  +                BasicBlock bb = getBBlock(m);
  +                if (bb == null) {
  +                    // the mark indicates a branch instruction
  +                    if (prev.length > 0) {
  +                        // the previous mark already has exits.
  +                        prev = makeBlock(prev.position + prev.length);
  +                        blocks.add(prev);
  +                    }
  +
  +                    prev.length = m.position + m.size - prev.position;
  +                    prev.exit = m.jump;
  +                    prev.stop = m.alwaysJmp;
               }
  +                else {
  +                    // the mark indicates a branch target
  +                    if (prev.length == 0) {
  +                        prev.length = m.position - prev.position;
  +                        bb.incoming++;
  +                        prev.exit = makeArray(bb);
           }
  -
  -        BasicBlock[] results = new BasicBlock[s];
  -        BasicBlock bb0 = (BasicBlock)targetArray[0];
  -        results[0] = bb0;
  -        t0 = bb0.position;
  -        int j = 1;
  -        for (int i = 1; i < size; i++) {
  -            BasicBlock bb = (BasicBlock)targetArray[i];
  -            int t = bb.position;
  -            if (t == t0)
  -                results[j - 1].inbound += bb.inbound;
               else {
  -                results[j - 1].updateLength(t);
  -                results[j++] = bb;
  -                t0 = t;
  +                        // the previous mark already has exits.
  +                        int prevPos = prev.position;
  +                        if (prevPos + prev.length < m.position) {
  +                            prev = makeBlock(prevPos + prev.length);
  +                            prev.length = m.position - prevPos;
  +                            // the incoming flow from dead code is not counted
  +                            // bb.incoming++;
  +                            prev.exit = makeArray(bb);
               }
           }
   
  -        results[j - 1].updateLength(endPos);
  -        return results;
  -    }
  -
  -    private static void markCatch(ExceptionTable et, int etOffset,
  -            BasicBlock[] blocks)
  -    {
  -        if (et == null)
  -            return;
  -
  -        int nblocks = blocks.length;
  -        int n = et.size();
  -        for (int i = 0; i < n; i++) {
  -            int start = et.startPc(i) + etOffset;
  -            int end = et.endPc(i) + etOffset;
  -            int handler = et.handlerPc(i) + etOffset;
  -            int type = et.catchType(i);
  -            for (int k = 0; k < nblocks; k++) {
  -                BasicBlock bb = blocks[k];
  -                int p = bb.position;
  -                if (start <= p && p < end)
  -                    bb.catchBlocks = new Branch(bb.catchBlocks, handler, type);
  -            }
  +                    blocks.add(bb);
  +                    prev = bb;
           }
       }
   
  -    /**
  -     * Initializes the first block by the given method descriptor.
  -     *
  -     * @param block             the first basic block that this method initializes.
  -     * @param className         a dot-separated fully qualified class name.
  -     *                          For example, <code>javassist.bytecode.stackmap.BasicBlock</code>.
  -     * @param methodDesc        method descriptor.
  -     * @param isStatic          true if the method is a static method.
  -     * @param isConstructor     true if the method is a constructor.
  -     */
  -    void initFirstBlock(int maxStack, int maxLocals, String className,
  -                        String methodDesc, boolean isStatic, boolean isConstructor)
  -        throws BadBytecode
  -    {
  -        if (methodDesc.charAt(0) != '(')
  -            throw new BadBytecode("no method descriptor: " + methodDesc);
  +            return (BasicBlock[])blocks.toArray(makeArray(blocks.size()));
  +        }
   
  -        stackTop = 0;
  -        stackTypes = new TypeData[maxStack];
  -        TypeData[] locals = new TypeData[maxLocals];
  -        if (isConstructor)
  -            locals[0] = new TypeData.UninitThis(className);
  -        else if (!isStatic)
  -            locals[0] = new TypeData.ClassName(className);
  -
  -        int n = isStatic ? -1 : 0;
  -        int i = 1;
  -        try {
  -            while ((i = descToTag(methodDesc, i, ++n, locals)) > 0)
  -                if (locals[n].is2WordType())
  -                    locals[++n] = TOP;
  -        }
  -        catch (StringIndexOutOfBoundsException e) {
  -            throw new BadBytecode("bad method descriptor: "
  -                                  + methodDesc);
  +        private static BasicBlock getBBlock(Mark m) {
  +            BasicBlock b = m.block;
  +            if (b != null && m.size > 0) {
  +                b.exit = m.jump;
  +                b.length = m.size;
  +                b.stop = m.alwaysJmp;
           }
   
  -        numLocals = n;
  -        localsTypes = locals;
  +            return b;
       }
   
  -    private static int descToTag(String desc, int i,
  -                                 int n, TypeData[] types)
  +        private void addCatchers(BasicBlock[] blocks, ExceptionTable et)
           throws BadBytecode
       {
  -        int i0 = i;
  -        int arrayDim = 0;
  -        char c = desc.charAt(i);
  -        if (c == ')')
  -            return 0;
  -
  -        while (c == '[') {
  -            ++arrayDim;
  -            c = desc.charAt(++i);
  -        }
  +            if (et == null)
  +                return;
   
  -        if (c == 'L') {
  -            int i2 = desc.indexOf(';', ++i);
  -            if (arrayDim > 0)
  -                types[n] = new TypeData.ClassName(desc.substring(i0, ++i2));
  -            else
  -                types[n] = new TypeData.ClassName(desc.substring(i0 + 1, ++i2 - 1)
  -                                                      .replace('/', '.'));
  -            return i2;
  -        }
  -        else if (arrayDim > 0) {
  -            types[n] = new TypeData.ClassName(desc.substring(i0, ++i));
  -            return i;
  -        }
  -        else {
  -            TypeData t = toPrimitiveTag(c);
  -            if (t == null)
  -                throw new BadBytecode("bad method descriptor: " + desc);
  -
  -            types[n] = t;
  -            return i + 1;
  +            int i = et.size();
  +            while (--i >= 0) {
  +                BasicBlock handler = find(blocks, et.handlerPc(i));
  +                int start = et.startPc(i);
  +                int end = et.endPc(i);
  +                int type = et.catchType(i);
  +                handler.incoming--;
  +                for (int k = 0; k < blocks.length; k++) {
  +                    BasicBlock bb = blocks[k];
  +                    int iPos = bb.position;
  +                    if (start <= iPos && iPos < end) {
  +                        bb.toCatch = new Catch(handler, type, bb.toCatch);
  +                        handler.incoming++;
           }
       }
  -
  -    private static TypeData toPrimitiveTag(char c) {
  -        switch (c) {
  -        case 'Z' :
  -        case 'C' :
  -        case 'B' :
  -        case 'S' :
  -        case 'I' :
  -            return INTEGER;
  -        case 'J' :
  -            return LONG;
  -        case 'F' :
  -            return FLOAT;
  -        case 'D' :
  -            return DOUBLE;
  -        case 'V' :
  -        default :
  -            return null;
           }
       }
  -
  -    public static String getRetType(String desc) {
  -        int i = desc.indexOf(')');
  -        if (i < 0)
  -            return "java.lang.Object";
  -
  -        char c = desc.charAt(i + 1);
  -        if (c == '[')
  -            return desc.substring(i + 1);
  -        else if (c == 'L')
  -            return desc.substring(i + 2, desc.length() - 1).replace('/', '.');
  -        else
  -            return "java.lang.Object";
       }
   }
  
  
  
  1.3       +129 -269  javassist/src/main/javassist/bytecode/stackmap/MapMaker.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: MapMaker.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/MapMaker.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -b -r1.2 -r1.3
  --- MapMaker.java	26 Apr 2007 14:58:16 -0000	1.2
  +++ MapMaker.java	6 May 2007 15:41:43 -0000	1.3
  @@ -22,11 +22,7 @@
    * Stack map maker.
    */
   public class MapMaker extends Tracer {
  -    private boolean moveon;     // used for returning another value from doOpcode().
  -    private boolean loopDetected;
  -    private int iteration;
  -    private BasicBlock[] blocks;
  -
  +    /*
       public static void main(String[] args) throws Exception {
           boolean useMain2 = args[0].equals("0");
           if (useMain2 && args.length > 1) {
  @@ -49,7 +45,7 @@
               MethodInfo minfo = (MethodInfo)minfos.get(i);
               CodeAttribute ca = minfo.getCodeAttribute();
               if (ca != null)
  -                ca.setAttribute(MapMaker.getMap(cp, minfo)); 
  +                ca.setAttribute(make(cp, minfo));
           }
   
           cc.writeFile("tmp");
  @@ -60,253 +56,162 @@
           //javassist.CtClass cc = cp.get(args[1]);
           javassist.CtClass cc = cp.makeClass(new java.io.FileInputStream(args[1]));
           MethodInfo minfo;
  -        MapMaker mm;
           if (args[2].equals("_init_"))
  -            // minfo = cc.getDeclaredConstructors()[0].getMethodInfo();
  -            minfo = cc.getClassInitializer().getMethodInfo();
  +            minfo = cc.getDeclaredConstructors()[0].getMethodInfo();
  +            // minfo = cc.getClassInitializer().getMethodInfo();
           else
               minfo = cc.getDeclaredMethod(args[2]).getMethodInfo();
   
  -        mm = makeMapMaker(cp, minfo);
  -        if (mm == null)
  -            System.out.println("single basic block");
  -        else {
  -            BasicBlock[] blocks = mm.getBlocks();
  +        CodeAttribute ca = minfo.getCodeAttribute();
  +        if (ca == null) {
  +            System.out.println("abstarct method");
  +            return;
  +        }
  +
  +        TypedBlock[] blocks = TypedBlock.makeBlocks(minfo, ca, false);
  +        MapMaker mm = new MapMaker(cp, minfo, ca);
  +        mm.make(blocks, ca.getCode());
               for (int i = 0; i < blocks.length; i++)
                   System.out.println(blocks[i]);
  -
  -            StackMapTable smt = mm.toStackMap();
  -        }
       }
  +    */
   
       /**
        * Computes the stack map table of the given method and returns it.
        * It returns null if the given method does not have to have a
        * stack map table.
        */
  -    public static StackMapTable getMap(ClassPool classes, MethodInfo minfo)
  -        throws BadBytecode
  -    {
  -        MapMaker mm = makeMapMaker(classes, minfo);
  -        if (mm == null)
  -            return null;
  -        else
  -            return mm.toStackMap();
  -    }
  -
  -    /**
  -     * Makes basic blocks with stack maps.  If the number of the basic blocks
  -     * is one, this method returns null.  If the given method info does not
  -     * include a code attribute, this method also returns null.
  -     */
  -    public static MapMaker makeMapMaker(ClassPool classes, MethodInfo minfo)
  +    public static StackMapTable make(ClassPool classes, MethodInfo minfo)
           throws BadBytecode
       {
           CodeAttribute ca = minfo.getCodeAttribute();
           if (ca == null)
               return null;
   
  -        CodeIterator ci = ca.iterator();
  -        ConstPool pool = minfo.getConstPool();
  -        ExceptionTable et = ca.getExceptionTable();
  -        BasicBlock[] blocks = BasicBlock.makeBlocks(ci, 0, ci.getCodeLength(),
  -                                                    et, 0, pool);
  -        if (blocks.length < 2)
  -            if (blocks.length == 0 || blocks[0].inbound < 1) 
  +        TypedBlock[] blocks = TypedBlock.makeBlocks(minfo, ca, true);
  +        if (blocks == null)
                   return null;
   
  -        boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
  -        int maxStack = ca.getMaxStack();
  -        int maxLocals = ca.getMaxLocals();
  -        BasicBlock top = blocks[0];
  -        String desc = minfo.getDescriptor();
  -        top.initFirstBlock(maxStack, maxLocals, pool.getClassName(), desc,
  -                           isStatic, minfo.isConstructor());
  -        String retType = BasicBlock.getRetType(desc);
  -        MapMaker mm = new MapMaker(classes, pool, maxStack, maxLocals,
  -                                   blocks, retType, blocks[0], 0);
  -        mm.make(ca.getCode(), et);
  -        return mm;
  +        MapMaker mm = new MapMaker(classes, minfo, ca);
  +        mm.make(blocks, ca.getCode());
  +        return mm.toStackMap(blocks);
       }
   
  -    /**
  -     * Constructs a tracer.
  -     */
  -    MapMaker(ClassPool classes, ConstPool cp,
  -             int maxStack, int maxLocals, BasicBlock[] bb,
  -             String retType, BasicBlock init, int iterate)
  -    {
  -        this(classes, cp, maxStack, maxLocals, bb, retType, iterate);
  -        TypeData[] srcTypes = init.localsTypes;
  -        copyFrom(srcTypes.length, srcTypes, this.localsTypes);
  +    public MapMaker(ClassPool classes, MethodInfo minfo, CodeAttribute ca) {
  +        super(classes, minfo.getConstPool(),
  +              ca.getMaxStack(), ca.getMaxLocals(),
  +              TypedBlock.getRetType(minfo.getDescriptor()));
       }
   
  -    private MapMaker(ClassPool classes, ConstPool cp,
  -            int maxStack, int maxLocals, BasicBlock[] bb,
  -            String retType, int iterateNo)
  -    {
  -        super(classes, cp, maxStack, maxLocals, retType);
  -        blocks = bb;
  -        loopDetected = false;
  -        iteration = iterateNo;
  +    protected MapMaker(MapMaker old, boolean copyStack) {
  +        super(old, copyStack);
       }
   
  -    public BasicBlock[] getBlocks() { return blocks; }
  -
       /**
  -     * Runs an analyzer.
  +     * Runs an analyzer (Phase 1 and 2).
        */
  -    void make(byte[] code, ExceptionTable et) throws BadBytecode {
  -        blocks[0].version = iteration;
  -        make(code, blocks[0]);
  -        if (loopDetected) {
  -            blocks[0].version = ++iteration;
  -            make(code, blocks[0]);
  -        }
  +    void make(TypedBlock[] blocks, byte[] code)
  +        throws BadBytecode
  +    {
  +        TypedBlock first = blocks[0];
  +        TypeData[] srcTypes = first.localsTypes;
  +        copyFrom(srcTypes.length, srcTypes, this.localsTypes);
  +        make(code, first);
   
           int n = blocks.length;
           for (int i = 0; i < n; i++)
               evalExpected(blocks[i]);
       }
   
  -    // Phase 1: Code Tracing
  +    // Phase 1
   
  -    private void make(byte[] code, BasicBlock bb)
  +    private void make(byte[] code, TypedBlock tb)
           throws BadBytecode
       {
  -        int pos = bb.position;
  -        int end = pos + bb.length;
  -        traceExceptions(code, bb.catchBlocks);
  -        moveon = true;
  -        while (moveon && pos < end)
  +        BasicBlock.Catch handlers = tb.toCatch;
  +        while (handlers != null) {
  +            traceException(code, handlers);
  +            handlers = handlers.next;
  +        }
  +
  +        int pos = tb.position;
  +        int end = pos + tb.length;
  +        while (pos < end)
               pos += doOpcode(pos, code);
   
  -        if (moveon && pos < code.length) {
  -            this.copyFrom(this);
  -            nextBlock(pos, code, 0);
  -        }
  +        if (tb.exit != null) {
  +            for (int i = 0; i < tb.exit.length; i++) {
  +                TypedBlock e = (TypedBlock)tb.exit[i];
  +                if (e.alreadySet())
  +                    mergeMap(e, true);
  +                else {
  +                    recordStackMap(e);
  +                    MapMaker maker = new MapMaker(this, true);
  +                    maker.make(code, e);
       }
  -
  -    private void nextBlock(int pos, byte[] code, int offset) throws BadBytecode {
  -        BasicBlock bb = BasicBlock.find(blocks, pos + offset);
  -        if (bb.alreadySet(iteration)) {
  -            mergeMap(stackTypes, bb.stackTypes);
  -            mergeMap(localsTypes, bb.localsTypes);
  -            mergeUsage(bb);
           }
  -        else {
  -            recordStackMap(bb);
  -            bb.version = iteration;
  -            MapMaker maker = new MapMaker(classPool, cpool, stackTypes.length,
  -                                localsTypes.length, blocks, returnType, iteration);
  -            maker.copyFrom(this);
  -            maker.make(code, bb);
  -            recordUsage(bb, maker);
  -            if (maker.loopDetected)
  -                this.loopDetected = true;
           }
       }
   
  -    private void traceExceptions(byte[] code, BasicBlock.Branch branches)
  +    private void traceException(byte[] code, TypedBlock.Catch handler)
           throws BadBytecode
       {
  -        while (branches != null) {
  -            int pos = branches.target;
  -            BasicBlock bb = BasicBlock.find(blocks, pos);
  -            if (bb.alreadySet(iteration)) {
  -                mergeMap(localsTypes, bb.localsTypes);
  -                mergeUsage(bb);
  -            }
  +        TypedBlock tb = (TypedBlock)handler.body;
  +        if (tb.alreadySet())
  +            mergeMap(tb, false);
               else {
  -                recordStackMap(bb, branches.typeIndex);
  -                bb.version = iteration;
  -                MapMaker maker = new MapMaker(classPool, cpool, stackTypes.length,
  -                                   localsTypes.length, blocks, returnType, iteration);
  +            recordStackMap(tb, handler.typeIndex);
  +            MapMaker maker = new MapMaker(this, false);
   
                   /* the following code is equivalent to maker.copyFrom(this)
                    * except stackTypes are not copied.
                    */ 
  -                maker.stackTypes[0] = bb.stackTypes[0].getSelf();
  +            maker.stackTypes[0] = tb.stackTypes[0].getSelf();
                   maker.stackTop = 1;
  -                TypeData[] srcTypes = this.localsTypes;
  -                copyFrom(srcTypes.length, srcTypes, maker.localsTypes);
  -
  -                maker.make(code, bb);
  -                recordUsage(bb, maker);
  -                if (maker.loopDetected)
  -                    this.loopDetected = true;
  -            }
  -
  -            branches = branches.next;
  +            maker.make(code, tb);
           }
       }
   
  -    private static void mergeMap(TypeData[] srcTypes, TypeData[] destTypes) {
  -        int n = srcTypes.length;
  -        for (int i = 0; i < n; i++) {
  -            TypeData s = srcTypes[i];
  -            TypeData d = destTypes[i];
  -            boolean sIsObj = false;
  -            boolean dIsObj = false;
  -            // s or b is null if it is TOP. 
  -            if (s != TOP && s.isObjectType())
  -                sIsObj = true;
  -
  -            if (d != TOP && d.isObjectType())
  -                dIsObj = true;
  -
  -            if (sIsObj && dIsObj)
  -                d.merge(s);
  -            else if (s != d)
  -                destTypes[i] = TOP;
  +    private void mergeMap(TypedBlock dest, boolean mergeStack) {
  +        boolean[] inputs = dest.inputs;
  +        int n = inputs.length;
  +        for (int i = 0; i < n; i++)
  +            if (inputs[i])
  +                merge(localsTypes[i], dest.localsTypes[i]); 
  +
  +        if (mergeStack) {
  +            n = stackTop;
  +            for (int i = 0; i < n; i++)
  +                merge(stackTypes[i], dest.stackTypes[i]);
           }
       }
   
  -    private void copyFrom(MapMaker src) {
  -        int sp = src.stackTop;
  -        this.stackTop = sp;
  -        copyFrom(sp, src.stackTypes, this.stackTypes);
  -        TypeData[] srcTypes = src.localsTypes;
  -        copyFrom(srcTypes.length, srcTypes, this.localsTypes);
  -    }
  +    private void merge(TypeData td, TypeData target) {
  +        boolean tdIsObj = false;
  +        boolean targetIsObj = false;
  +        // td or target is null if it is TOP. 
  +        if (td != TOP && td.isObjectType())
  +            tdIsObj = true;
   
  -    private static int copyFrom(int n, TypeData[] srcTypes, TypeData[] destTypes) {
  -        int k = -1;
  -        for (int i = 0; i < n; i++) {
  -            TypeData t = srcTypes[i];
  -            destTypes[i] = t == null ? null : t.getSelf();
  -            if (t != TOP)
  -                if (t.is2WordType())
  -                    k = i + 1;
  -                else
  -                    k = i;
  -        }
  +        if (target != TOP && target.isObjectType())
  +            targetIsObj = true;
   
  -        return k + 1;
  +        if (tdIsObj && targetIsObj)
  +            target.merge(td);
       }
   
  -    private void recordStackMap(BasicBlock target)
  +    private void recordStackMap(TypedBlock target)
           throws BadBytecode
       {
  -        int n = localsTypes.length;
  -        TypeData[] tLocalsTypes = new TypeData[n];
  -        int k = copyFrom(n, localsTypes, tLocalsTypes);
  -
  -        n = stackTypes.length;
  -        TypeData[] tStackTypes = new TypeData[n];
  +        TypeData[] tStackTypes = new TypeData[stackTypes.length];
           int st = stackTop;
           copyFrom(st, stackTypes, tStackTypes);
  -
  -        target.setStackMap(st, tStackTypes, k, tLocalsTypes);
  +        recordStackMap0(target, st, tStackTypes);
       }
   
  -    private void recordStackMap(BasicBlock target, int exceptionType)
  +    private void recordStackMap(TypedBlock target, int exceptionType)
           throws BadBytecode
       {
  -        int n = localsTypes.length;
  -        TypeData[] tLocalsTypes = new TypeData[n];
  -        int k = copyFrom(n, localsTypes, tLocalsTypes);
  -
           String type;
           if (exceptionType == 0)
               type = "java.lang.Throwable";
  @@ -316,44 +221,27 @@
           TypeData[] tStackTypes = new TypeData[stackTypes.length];
           tStackTypes[0] = new TypeData.ClassName(type);
   
  -        target.setStackMap(1, tStackTypes, k, tLocalsTypes);
  +        recordStackMap0(target, 1, tStackTypes);
       }
   
  -    private void recordUsage(BasicBlock target, MapMaker next) {
  -        int[] nextUsage = next.localsUsage;
  -        TypeData[] tData = target.localsTypes;
  -        int n = tData.length;
  -        for (int i = blocks[0].numLocals; i < n; i++)
  -            if (nextUsage[i] == READ)
  -                readLocal(i);
  -            else
  -                tData[i] = TOP;
  +    private void recordStackMap0(TypedBlock target, int st, TypeData[] tStackTypes)
  +        throws BadBytecode
  +    {
  +        int n = localsTypes.length;
  +        TypeData[] tLocalsTypes = new TypeData[n];
  +        int k = copyFrom(n, localsTypes, tLocalsTypes);
   
  -        int[] usage = new int[nextUsage.length];
  -        n = usage.length;
  +        boolean[] inputs = target.inputs;
           for (int i = 0; i < n; i++)
  -            usage[i] = nextUsage[i];
  -
  -        target.localsUsage = usage;
  -    }
  +            if (!inputs[i])
  +                tLocalsTypes[i] = TOP;
   
  -    private void mergeUsage(BasicBlock target) {
  -        int[] usage = target.localsUsage;
  -        if (usage == null) {
  -            // detected a loop.
  -            loopDetected = true;
  -        }
  -        else {
  -            int n = usage.length;
  -            for (int i = 0; i < n; i++)
  -                if (usage[i] == READ)
  -                    readLocal(i);
  -        }
  +        target.setStackMap(st, tStackTypes, k, tLocalsTypes);
       }
   
       // Phase 2
   
  -    void evalExpected(BasicBlock target) throws BadBytecode {
  +    void evalExpected(TypedBlock target) throws BadBytecode {
           ClassPool cp = classPool;
           evalExpected(cp, target.stackTop, target.stackTypes);
           TypeData[] types = target.localsTypes;
  @@ -373,20 +261,19 @@
   
       // Phase 3
   
  -    public StackMapTable toStackMap() {
  -        BasicBlock[] blocks = this.blocks;
  +    public StackMapTable toStackMap(TypedBlock[] blocks) {
           StackMapTable.Writer writer = new StackMapTable.Writer(32);
           int n = blocks.length;
  -        BasicBlock prev = blocks[0];
  +        TypedBlock prev = blocks[0];
           int offsetDelta = prev.length;
  -        if (prev.inbound > 0) {     // the first instruction is a branch target.
  +        if (prev.incoming > 0) {     // the first instruction is a branch target.
               writer.sameFrame(0);
               offsetDelta--;
           }
   
           for (int i = 1; i < n; i++) {
  -            BasicBlock bb = blocks[i];
  -            if (bb.inbound > 0) {
  +            TypedBlock bb = blocks[i];
  +            if (isTarget(bb, blocks[i - 1])) {
                   bb.resetNumLocals();
                   int diffL = stackMapDiff(prev.numLocals, prev.localsTypes,
                                            bb.numLocals, bb.localsTypes);
  @@ -402,8 +289,21 @@
           return writer.toStackMapTable(cpool);
       }
   
  -    private void toStackMapBody(StackMapTable.Writer writer, BasicBlock bb,
  -                                int diffL, int offsetDelta, BasicBlock prev) {
  +    /**
  +     * Returns true if cur is a branch target.
  +     */
  +    private boolean isTarget(TypedBlock cur, TypedBlock prev) {
  +        int in = cur.incoming;
  +        if (in > 1)
  +            return true;
  +        else if (in < 1)
  +            return false;
  +
  +        return prev.stop;
  +    }
  +
  +    private void toStackMapBody(StackMapTable.Writer writer, TypedBlock bb,
  +                                int diffL, int offsetDelta, TypedBlock prev) {
           // if diffL is -100, two TypeData arrays do not share
           // any elements.
   
  @@ -521,44 +421,4 @@
   
           return num;
       }
  -
  -    // Branch actions
  -
  -    protected void visitBranch(int pos, byte[] code, int offset) throws BadBytecode {
  -        nextBlock(pos, code, offset);
  -    }
  -
  -    protected void visitGoto(int pos, byte[] code, int offset) throws BadBytecode {
  -        nextBlock(pos, code, offset);
  -        moveon = false;
  -    }
  -
  -    protected void visitTableSwitch(int pos, byte[] code, int n, int offsetPos, int defaultOffset)
  -        throws BadBytecode
  -    {
  -        nextBlock(pos, code, defaultOffset);
  -        for (int i = 0; i < n; i++) {
  -            nextBlock(pos, code, ByteArray.read32bit(code, offsetPos));
  -            offsetPos += 4;
  -        }
  -
  -        moveon = false;
  -    }
  -
  -    protected void visitLookupSwitch(int pos, byte[] code, int n, int pairsPos, int defaultOffset)
  -        throws BadBytecode
  -    {
  -        nextBlock(pos, code, defaultOffset);
  -        pairsPos += 4;
  -        for (int i = 0; i < n; i++) {
  -            nextBlock(pos, code, ByteArray.read32bit(code, pairsPos));
  -            pairsPos += 8;
  -        }
  -
  -        moveon = false;
  -    }
  -
  -    protected void visitReturn(int pos, byte[] code) { moveon = false; }
  -
  -    protected void visitThrow(int pos, byte[] code) { moveon = false; }
   }
  
  
  
  1.3       +16 -1     javassist/src/main/javassist/bytecode/stackmap/TypeData.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: TypeData.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/TypeData.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -b -r1.2 -r1.3
  --- TypeData.java	26 Apr 2007 14:58:16 -0000	1.2
  +++ TypeData.java	6 May 2007 15:41:43 -0000	1.3
  @@ -122,7 +122,7 @@
       protected static abstract class TypeName extends TypeData {
           protected ArrayList equivalences;
   
  -        private String expectedName;
  +        protected String expectedName;
           private CtClass cache;
           private boolean evalDone;
   
  @@ -275,6 +275,8 @@
               }
           }
   
  +        /* See also NullType.getExpected().
  +         */
           public String getExpected() throws BadBytecode {
               ArrayList equiv = equivalences;
               if (equiv.size() == 1)
  @@ -359,6 +361,19 @@
               else
                   return super.getTypeData2(cp, type);
           }
  +
  +        public String getExpected() throws BadBytecode {
  +            String en = expectedName;
  +            if (en == null) {
  +                ArrayList equiv = equivalences;
  +                if (equiv.size() == 1)
  +                    return getName();
  +                else
  +                    return "java.lang.Object";
  +            }
  +            else
  +                return en;
  +        }
       }
   
       /**
  
  
  
  1.3       +28 -32    javassist/src/main/javassist/bytecode/stackmap/Tracer.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Tracer.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/Tracer.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -b -r1.2 -r1.3
  --- Tracer.java	26 Apr 2007 14:58:16 -0000	1.2
  +++ Tracer.java	6 May 2007 15:41:43 -0000	1.3
  @@ -36,11 +36,6 @@
       protected TypeData[] stackTypes;
       protected TypeData[] localsTypes;
   
  -    static final int UNKNOWN = 0;
  -    static final int READ = 1;
  -    static final int UPDATED = 2;
  -    protected int[] localsUsage;
  -
       public Tracer(ClassPool classes, ConstPool cp, int maxStack, int maxLocals,
                     String retType) {
           classPool = classes;
  @@ -49,21 +44,37 @@
           stackTop = 0;
           stackTypes = new TypeData[maxStack];
           localsTypes = new TypeData[maxLocals];
  -        localsUsage = new int[maxLocals];
       }
   
  -    /* If the type is LONG or DOUBLE,
  -     * the next local variable is also read.
  -     * IINC (or WIDE IINC) calls only readLocal() but it does not call writeLocal().
  -     */
  -    protected final void readLocal(int reg) {
  -        if (localsUsage[reg] == UNKNOWN)
  -            localsUsage[reg] = READ;
  +    public Tracer(Tracer t, boolean copyStack) {
  +        classPool = t.classPool;
  +        cpool = t.cpool;
  +        returnType = t.returnType;
  +
  +        stackTop = t.stackTop;
  +        int size = t.stackTypes.length;
  +        stackTypes = new TypeData[size];
  +        if (copyStack)
  +            copyFrom(t.stackTop, t.stackTypes, stackTypes);
  +
  +        int size2 = t.localsTypes.length;
  +        localsTypes = new TypeData[size2];
  +        copyFrom(size2, t.localsTypes, localsTypes);
  +    }
  +
  +    protected static int copyFrom(int n, TypeData[] srcTypes, TypeData[] destTypes) {
  +        int k = -1;
  +        for (int i = 0; i < n; i++) {
  +            TypeData t = srcTypes[i];
  +            destTypes[i] = t == TOP ? TOP : t.getSelf();
  +            if (t != TOP)
  +                if (t.is2WordType())
  +                    k = i + 1;
  +                else
  +                    k = i;
       }
   
  -    protected final void writeLocal(int reg) {
  -        if (localsUsage[reg] == UNKNOWN)
  -            localsUsage[reg] = UPDATED;
  +        return k + 1;
       }
   
       /**
  @@ -192,7 +203,6 @@
           case Opcode.ILOAD_2 :
           case Opcode.ILOAD_3 :
               stackTypes[stackTop++] = INTEGER;
  -            readLocal(op - Opcode.ILOAD_0);
               break;
           case Opcode.LLOAD_0 :
           case Opcode.LLOAD_1 :
  @@ -200,14 +210,12 @@
           case Opcode.LLOAD_3 :
               stackTypes[stackTop++] = LONG;
               stackTypes[stackTop++] = TOP;
  -            readLocal(op - Opcode.LLOAD_0);
               break;
           case Opcode.FLOAD_0 :
           case Opcode.FLOAD_1 :
           case Opcode.FLOAD_2 :
           case Opcode.FLOAD_3 :
               stackTypes[stackTop++] = FLOAT;
  -            readLocal(op - Opcode.FLOAD_0);
               break;
           case Opcode.DLOAD_0 :
           case Opcode.DLOAD_1 :
  @@ -215,7 +223,6 @@
           case Opcode.DLOAD_3 :
               stackTypes[stackTop++] = DOUBLE;
               stackTypes[stackTop++] = TOP;
  -            readLocal(op - Opcode.DLOAD_0);
               break;
           case Opcode.ALOAD_0 :
           case Opcode.ALOAD_1 :
  @@ -223,7 +230,6 @@
           case Opcode.ALOAD_3 :
               reg = op - Opcode.ALOAD_0;
               stackTypes[stackTop++] = localsTypes[reg];
  -            readLocal(reg);
               break;
           case Opcode.IALOAD :
               stackTypes[--stackTop - 1] = INTEGER;
  @@ -293,13 +299,11 @@
           if (type.is2WordType())
               stackTypes[stackTop++] = TOP;
   
  -        readLocal(localVar);
           return 2;
       }
   
       private int doALOAD(int localVar) { // int localVar, TypeData type) {
           stackTypes[stackTop++] = localsTypes[localVar];
  -        readLocal(localVar);
           return 2;
       }
   
  @@ -323,7 +327,6 @@
           case Opcode.ISTORE_3 :
             { int var = op - Opcode.ISTORE_0;
               localsTypes[var] = INTEGER;
  -            writeLocal(var);
               stackTop--; }
               break;
           case Opcode.LSTORE_0 :
  @@ -333,7 +336,6 @@
             { int var = op - Opcode.LSTORE_0;
               localsTypes[var] = LONG;
               localsTypes[var + 1] = TOP;
  -            writeLocal(var);
               stackTop -= 2; }
               break;
           case Opcode.FSTORE_0 :
  @@ -342,7 +344,6 @@
           case Opcode.FSTORE_3 :
             { int var = op - Opcode.FSTORE_0;
               localsTypes[var] = FLOAT;
  -            writeLocal(var);
               stackTop--; }
               break;
           case Opcode.DSTORE_0 :
  @@ -352,7 +353,6 @@
             { int var = op - Opcode.DSTORE_0;
               localsTypes[var] = DOUBLE;
               localsTypes[var + 1] = TOP;
  -            writeLocal(var);
               stackTop -= 2; }
               break;
           case Opcode.ASTORE_0 :
  @@ -424,7 +424,6 @@
   
       private int doXSTORE(int index, TypeData type) {
           stackTop--;
  -        writeLocal(index);
           localsTypes[index] = type;
           if (type.is2WordType()) {
               stackTop--;
  @@ -436,7 +435,6 @@
   
       private int doASTORE(int index) {
           stackTop--;
  -        writeLocal(index);
           // implicit upcast might be done.
           localsTypes[index] = stackTypes[stackTop].copy();
   
  @@ -461,7 +459,6 @@
   
           switch (op) {
           case Opcode.IINC :
  -            readLocal(code[pos + 1] & 0xff);
               // this does not call writeLocal().
               return 3;
           case Opcode.I2L :
  @@ -705,7 +702,6 @@
               int index = ByteArray.readU16bit(code, pos + 2);
               return doASTORE(index); }
           case Opcode.IINC :
  -            readLocal(ByteArray.readU16bit(code, pos + 2));
               // this does not call writeLocal().
               return 6;
           case Opcode.RET :
  
  
  
  1.1      date: 2007/05/06 15:41:43;  author: chiba;  state: Exp;javassist/src/main/javassist/bytecode/stackmap/TypedBlock.java
  
  Index: TypedBlock.java
  ===================================================================
  package javassist.bytecode.stackmap;
  
  import javassist.bytecode.*;
  
  public class TypedBlock extends BasicBlock {
      public int stackTop, numLocals;
      public TypeData[] stackTypes, localsTypes;
  
      // set by a Liveness object.
      public boolean[] inputs;
      public boolean updating;
      public int status;
      public byte[] localsUsage;
  
      /**
       * Divides the method body into basic blocks.
       * The type information of the first block is initialized.
       *
       * @param optmize       if it is true and the method does not include
       *                      branches, this method returns null.
       */
      public static TypedBlock[] makeBlocks(MethodInfo minfo, CodeAttribute ca,
                                            boolean optimize)
          throws BadBytecode
      {
          TypedBlock[] blocks = (TypedBlock[])new Maker().make(minfo);
          if (optimize && blocks.length < 2)
              if (blocks.length == 0 || blocks[0].incoming == 0)
                  return null;
  
          ConstPool pool = minfo.getConstPool();
          boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
          blocks[0].initFirstBlock(ca.getMaxStack(), ca.getMaxLocals(),
                                   pool.getClassName(), minfo.getDescriptor(),
                                   isStatic, minfo.isConstructor());
          new Liveness().compute(ca.iterator(), blocks, ca.getMaxLocals(),
                                 blocks[0].localsTypes);
          return blocks;
      }
  
      protected TypedBlock(int pos) {
          super(pos);
          localsTypes = null;
          inputs = null;
          updating = false;
      }
  
      protected void toString2(StringBuffer sbuf) {
          super.toString2(sbuf);
          sbuf.append(",\n stack={");
          printTypes(sbuf, stackTop, stackTypes);
          sbuf.append("}, locals={");
          printTypes(sbuf, numLocals, localsTypes);
          sbuf.append("}, inputs={");
          if (inputs != null)
              for (int i = 0; i < inputs.length; i++)
                  sbuf.append(inputs[i] ? "1, " : "0, ");
  
          sbuf.append('}');
      }
  
      private void printTypes(StringBuffer sbuf, int size,
                              TypeData[] types) {
          if (types == null)
              return;
  
          for (int i = 0; i < size; i++) {
              if (i > 0)
                  sbuf.append(", ");
  
              TypeData td = types[i];
              sbuf.append(td == null ? "<>" : td.toString());
          }
      }
  
      public boolean alreadySet() {
          return localsTypes != null;
      }
  
      public void setStackMap(int st, TypeData[] stack, int nl, TypeData[] locals)
          throws BadBytecode
      {
          stackTop = st;
          stackTypes = stack;
          numLocals = nl;
          localsTypes = locals;
      }
  
      /*
       * Computes the correct value of numLocals.
       */
      public void resetNumLocals() {
          if (localsTypes != null) {
              int nl = localsTypes.length;
              while (nl > 0 && localsTypes[nl - 1] == TypeTag.TOP) {
                  if (nl > 1) {
                      TypeData td = localsTypes[nl - 2];
                      if (td == TypeTag.LONG || td == TypeTag.DOUBLE)
                          break;
                  }
  
                  --nl;
              }
  
              numLocals = nl;
          }
      }
  
      public static class Maker extends BasicBlock.Maker {
          protected BasicBlock makeBlock(int pos) {
              return new TypedBlock(pos);
          }
  
          protected BasicBlock[] makeArray(int size) {
              return new TypedBlock[size];
          }
      }
  
      /**
       * Initializes the first block by the given method descriptor.
       *
       * @param block             the first basic block that this method initializes.
       * @param className         a dot-separated fully qualified class name.
       *                          For example, <code>javassist.bytecode.stackmap.BasicBlock</code>.
       * @param methodDesc        method descriptor.
       * @param isStatic          true if the method is a static method.
       * @param isConstructor     true if the method is a constructor.
       */
      void initFirstBlock(int maxStack, int maxLocals, String className,
                          String methodDesc, boolean isStatic, boolean isConstructor)
          throws BadBytecode
      {
          if (methodDesc.charAt(0) != '(')
              throw new BadBytecode("no method descriptor: " + methodDesc);
  
          stackTop = 0;
          stackTypes = new TypeData[maxStack];
          TypeData[] locals = new TypeData[maxLocals];
          if (isConstructor)
              locals[0] = new TypeData.UninitThis(className);
          else if (!isStatic)
              locals[0] = new TypeData.ClassName(className);
  
          int n = isStatic ? -1 : 0;
          int i = 1;
          try {
              while ((i = descToTag(methodDesc, i, ++n, locals)) > 0)
                  if (locals[n].is2WordType())
                      locals[++n] = TypeTag.TOP;
          }
          catch (StringIndexOutOfBoundsException e) {
              throw new BadBytecode("bad method descriptor: "
                                    + methodDesc);
          }
  
          numLocals = n;
          localsTypes = locals;
      }
  
      private static int descToTag(String desc, int i,
                                   int n, TypeData[] types)
          throws BadBytecode
      {
          int i0 = i;
          int arrayDim = 0;
          char c = desc.charAt(i);
          if (c == ')')
              return 0;
  
          while (c == '[') {
              ++arrayDim;
              c = desc.charAt(++i);
          }
  
          if (c == 'L') {
              int i2 = desc.indexOf(';', ++i);
              if (arrayDim > 0)
                  types[n] = new TypeData.ClassName(desc.substring(i0, ++i2));
              else
                  types[n] = new TypeData.ClassName(desc.substring(i0 + 1, ++i2 - 1)
                                                        .replace('/', '.'));
              return i2;
          }
          else if (arrayDim > 0) {
              types[n] = new TypeData.ClassName(desc.substring(i0, ++i));
              return i;
          }
          else {
              TypeData t = toPrimitiveTag(c);
              if (t == null)
                  throw new BadBytecode("bad method descriptor: " + desc);
  
              types[n] = t;
              return i + 1;
          }
      }
  
      private static TypeData toPrimitiveTag(char c) {
          switch (c) {
          case 'Z' :
          case 'C' :
          case 'B' :
          case 'S' :
          case 'I' :
              return TypeTag.INTEGER;
          case 'J' :
              return TypeTag.LONG;
          case 'F' :
              return TypeTag.FLOAT;
          case 'D' :
              return TypeTag.DOUBLE;
          case 'V' :
          default :
              return null;
          }
      }
  
      public static String getRetType(String desc) {
          int i = desc.indexOf(')');
          if (i < 0)
              return "java.lang.Object";
  
          char c = desc.charAt(i + 1);
          if (c == '[')
              return desc.substring(i + 1);
          else if (c == 'L')
              return desc.substring(i + 2, desc.length() - 1).replace('/', '.');
          else
              return "java.lang.Object";
      }
  }
  
  
  
  1.1      date: 2007/05/06 15:41:43;  author: chiba;  state: Exp;javassist/src/main/javassist/bytecode/stackmap/Liveness.java
  
  Index: Liveness.java
  ===================================================================
  /*
   * Javassist, a Java-bytecode translator toolkit.
   * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
   *
   * The contents of this file are subject to the Mozilla Public License Version
   * 1.1 (the "License"); you may not use this file except in compliance with
   * the License.  Alternatively, the contents of this file may be used under
   * the terms of the GNU Lesser General Public License Version 2.1 or later.
   *
   * Software distributed under the License is distributed on an "AS IS" basis,
   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   * for the specific language governing rights and limitations under the
   * License.
   */
  
   package javassist.bytecode.stackmap;
  
  import javassist.bytecode.*;
  
  public class Liveness {
      protected static final byte UNKNOWN = 0;
      protected static final byte READ = 1;
      protected static final byte UPDATED = 2;
      protected byte[] localsUsage;
  
      /**
       * If true, all the arguments become alive within the whole method body.
       *
       * To correctly compute a stack map table, all the arguments must
       * be alive (localsUsage[?] must be READ) at least in the first block.
       */
      public static boolean useArgs = true;
  
      public void compute(CodeIterator ci, TypedBlock[] blocks, int maxLocals,
                          TypeData[] args)
          throws BadBytecode
      {
          computeUsage(ci, blocks, maxLocals);
          if (useArgs)
              useAllArgs(blocks, args);
  
          computeLiveness1(blocks[0]);
          while (hasChanged(blocks))
              computeLiveness2(blocks[0]);
      }
  
      private void useAllArgs(TypedBlock[] blocks, TypeData[] args) {
          for (int k = 0; k < blocks.length; k++) {
              byte[] usage = blocks[k].localsUsage;
              for (int i = 0; i < args.length; i++)
                  if (args[i] != TypeTag.TOP)
                      usage[i] = READ;
          }
      }
  
      static final int NOT_YET = 0;
      static final int CHANGED_LAST = 1;
      static final int DONE = 2;
      static final int CHANGED_NOW = 3;
  
      private void computeLiveness1(TypedBlock tb) {
          if (tb.updating) {
              computeLiveness1u(tb);
              return;
          }
  
          if (tb.inputs != null)
              return;
  
          tb.updating = true;
          byte[] usage = tb.localsUsage;
          int n = usage.length;
          boolean[] in = new boolean[n];
          for (int i = 0; i < n; i++)
              in[i] = usage[i] == READ;
  
          BasicBlock.Catch handlers = tb.toCatch;
          while (handlers != null) {
              TypedBlock h = (TypedBlock)handlers.body;
              computeLiveness1(h);
              for (int k = 0; k < n; k++)
                  if (h.inputs[k])
                      in[k] = true;
  
              handlers = handlers.next;
          }
  
          if (tb.exit != null) {
              for (int i = 0; i < tb.exit.length; i++) {
                  TypedBlock e = (TypedBlock)tb.exit[i];
                  computeLiveness1(e);
                  for (int k = 0; k < n; k++)
                      if (!in[k])
                          in[k] = usage[k] == UNKNOWN && e.inputs[k];
              }
          }
  
          tb.updating = false;
          if (tb.inputs == null) {
              tb.inputs = in;
              tb.status = DONE;
          }
          else {
              for (int i = 0; i < n; i++)
                  if (in[i] && !tb.inputs[i]) {
                      tb.inputs[i] = true; 
                      tb.status = CHANGED_NOW;
                  }
          }
      }
  
      private void computeLiveness1u(TypedBlock tb) {
          if (tb.inputs == null) {
              byte[] usage = tb.localsUsage;
              int n = usage.length;
              boolean[] in = new boolean[n];
              for (int i = 0; i < n; i++)
                  in[i] = usage[i] == READ;
  
              tb.inputs = in;
              tb.status = DONE;
          }
      }
  
      private void computeLiveness2(TypedBlock tb) {
          if (tb.updating || tb.status >= DONE)
              return;
  
          tb.updating = true;
          if (tb.exit == null)
              tb.status = DONE;
          else {
              boolean changed = false;
              for (int i = 0; i < tb.exit.length; i++) {
                  TypedBlock e = (TypedBlock)tb.exit[i];
                  computeLiveness2(e);
                  if (e.status != DONE)
                      changed = true;
              }
  
              if (changed) {
                  changed = false;
                  byte[] usage = tb.localsUsage;
                  int n = usage.length;
                  for (int i = 0; i < tb.exit.length; i++) {
                      TypedBlock e = (TypedBlock)tb.exit[i];
                      if (e.status != DONE)
                          for (int k = 0; k < n; k++)
                              if (!tb.inputs[k]) {
                                  if (usage[k] == UNKNOWN && e.inputs[k]) {
                                      tb.inputs[k] = true;
                                      changed = true;
                                  }
                              }
                  }
  
                  tb.status = changed ? CHANGED_NOW : DONE;
              }
              else
                  tb.status = DONE;
          }
  
          if (computeLiveness2except(tb))
              tb.status = CHANGED_NOW;
  
          tb.updating = false;
      }
  
      private boolean computeLiveness2except(TypedBlock tb) {
          BasicBlock.Catch handlers = tb.toCatch;
          boolean changed = false;
          while (handlers != null) {
              TypedBlock h = (TypedBlock)handlers.body;
              computeLiveness2(h);
              if (h.status != DONE) {
                  boolean[] in = tb.inputs;
                  int n = in.length;
                  for (int k = 0; k < n; k++)
                      if (!in[k] && h.inputs[k]) {
                          in[k] = true;
                          changed = true;
                      }
              }
  
              handlers = handlers.next;
          }
  
          return changed;
      }
  
      private boolean hasChanged(TypedBlock[] blocks) {
          int n = blocks.length;
          boolean changed = false;
          for (int i = 0; i < n; i++) {
              TypedBlock tb = blocks[i];
              if (tb.status == DONE)
                  tb.status = NOT_YET;
              else {
                  tb.status = CHANGED_LAST;
                  changed = true;
              }
          }
  
          return changed;
      }
  
      private void computeUsage(CodeIterator ci, TypedBlock[] blocks, int maxLocals)
          throws BadBytecode
      {
          int n = blocks.length;
          for (int i = 0; i < n; i++) {
              TypedBlock tb = blocks[i];
              localsUsage = tb.localsUsage = new byte[maxLocals];
              int pos = tb.position;
              analyze(ci, pos, pos + tb.length);
              localsUsage = null;
          }
      }
  
      protected final void readLocal(int reg) {
          if (localsUsage[reg] == UNKNOWN)
              localsUsage[reg] = READ;
      }
  
      protected final void writeLocal(int reg) {
          if (localsUsage[reg] == UNKNOWN)
              localsUsage[reg] = UPDATED;
      }
  
      protected void analyze(CodeIterator ci, int begin, int end)
          throws BadBytecode
      {
          ci.begin();
          ci.move(begin);
          while (ci.hasNext()) {
              int index = ci.next();
              if (index >= end)
                  break;
  
              int op = ci.byteAt(index);
              if (op < 96)
                  if (op < 54)
                      doOpcode0_53(ci, index, op);
                  else
                      doOpcode54_95(ci, index, op);
              else
                  if (op == Opcode.IINC) {
                      // this does not call writeLocal().
                      readLocal(ci.byteAt(index + 1));
                  }
                  else if (op == Opcode.WIDE)
                      doWIDE(ci, index);
          }
      }
  
      private void doOpcode0_53(CodeIterator ci, int pos, int op) {
          switch (op) {
          case Opcode.ILOAD :
          case Opcode.LLOAD :
          case Opcode.FLOAD :
          case Opcode.DLOAD :
          case Opcode.ALOAD :
              readLocal(ci.byteAt(pos + 1));
              break;
          case Opcode.ILOAD_0 :
          case Opcode.ILOAD_1 :
          case Opcode.ILOAD_2 :
          case Opcode.ILOAD_3 :
              readLocal(op - Opcode.ILOAD_0);
              break;
          case Opcode.LLOAD_0 :
          case Opcode.LLOAD_1 :
          case Opcode.LLOAD_2 :
          case Opcode.LLOAD_3 :
              readLocal(op - Opcode.LLOAD_0);
              break;
          case Opcode.FLOAD_0 :
          case Opcode.FLOAD_1 :
          case Opcode.FLOAD_2 :
          case Opcode.FLOAD_3 :
              readLocal(op - Opcode.FLOAD_0);
              break;
          case Opcode.DLOAD_0 :
          case Opcode.DLOAD_1 :
          case Opcode.DLOAD_2 :
          case Opcode.DLOAD_3 :
              readLocal(op - Opcode.DLOAD_0);
              break;
          case Opcode.ALOAD_0 :
          case Opcode.ALOAD_1 :
          case Opcode.ALOAD_2 :
          case Opcode.ALOAD_3 :
              readLocal(op - Opcode.ALOAD_0);
              break;
          }
      }
  
      private void doOpcode54_95(CodeIterator ci, int pos, int op) {
          switch (op) {
          case Opcode.ISTORE :
          case Opcode.LSTORE :
          case Opcode.FSTORE :
          case Opcode.DSTORE :
          case Opcode.ASTORE :
              writeLocal(ci.byteAt(pos + 1));
              break;
          case Opcode.ISTORE_0 :
          case Opcode.ISTORE_1 :
          case Opcode.ISTORE_2 :
          case Opcode.ISTORE_3 :
              writeLocal(op - Opcode.ISTORE_0);
              break;
          case Opcode.LSTORE_0 :
          case Opcode.LSTORE_1 :
          case Opcode.LSTORE_2 :
          case Opcode.LSTORE_3 :
              writeLocal(op - Opcode.LSTORE_0);
              break;
          case Opcode.FSTORE_0 :
          case Opcode.FSTORE_1 :
          case Opcode.FSTORE_2 :
          case Opcode.FSTORE_3 :
              writeLocal(op - Opcode.FSTORE_0);
              break;
          case Opcode.DSTORE_0 :
          case Opcode.DSTORE_1 :
          case Opcode.DSTORE_2 :
          case Opcode.DSTORE_3 :
              writeLocal(op - Opcode.DSTORE_0);
              break;
          case Opcode.ASTORE_0 :
          case Opcode.ASTORE_1 :
          case Opcode.ASTORE_2 :
          case Opcode.ASTORE_3 :
              writeLocal(op - Opcode.ASTORE_0);
              break;
          }
      }
  
      private void doWIDE(CodeIterator ci, int pos) throws BadBytecode {
          int op = ci.byteAt(pos + 1);
          int var = ci.u16bitAt(pos + 2);
          switch (op) {
          case Opcode.ILOAD :
          case Opcode.LLOAD :
          case Opcode.FLOAD :
          case Opcode.DLOAD :
          case Opcode.ALOAD :
              readLocal(var);
              break;
          case Opcode.ISTORE :
          case Opcode.LSTORE :
          case Opcode.FSTORE :
          case Opcode.DSTORE :
          case Opcode.ASTORE :
              writeLocal(var);
              break;
          case Opcode.IINC :
              readLocal(var);
              // this does not call writeLocal().
              break;
          }
      }
  }
  
  
  



More information about the jboss-cvs-commits mailing list