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

Shigeru Chiba chiba at is.titech.ac.jp
Thu Apr 26 10:58:16 EDT 2007


  User: chiba   
  Date: 07/04/26 10:58:16

  Modified:    src/main/javassist/bytecode/stackmap     BasicBlock.java
                        MapMaker.java TypeData.java Tracer.java
  Log:
  snapshot.  I am still working on stackmap support.
  
  Revision  Changes    Path
  1.4       +81 -15    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.3
  retrieving revision 1.4
  diff -u -b -r1.3 -r1.4
  --- BasicBlock.java	10 Apr 2007 16:32:32 -0000	1.3
  +++ BasicBlock.java	26 Apr 2007 14:58:16 -0000	1.4
  @@ -24,6 +24,16 @@
       public int stackTop, numLocals;
       public TypeData[] stackTypes, localsTypes;
   
  +    /* 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;
  +
  +    /* a flag used by MapMaker#recordUsage()
  +     */
  +    public int[] localsUsage;
  +
       /* 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
  @@ -32,6 +42,22 @@
        */
       public int inbound;
   
  +    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;
  +        }
  +    }
  +
  +    /* A list of catch clauses that a thread may jump
  +     * from this block to.
  +     */
  +    public Branch catchBlocks;
  +
       /* 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"));
  @@ -44,9 +70,13 @@
           stackTop = numLocals = 0;
           stackTypes = localsTypes = null;
           inbound = 1;
  +        localsUsage = null;
  +        catchBlocks = null;
       }
   
  -    public boolean alreadySet() { return stackTypes != null; }
  +    public boolean alreadySet(int ver) {
  +        return stackTypes != null && ver == version;
  +    }
   
       /*
        * Computes the correct value of numLocals.
  @@ -56,8 +86,15 @@
       public void resetNumLocals() {
           if (localsTypes != null) {
               int nl = numLocals;
  -            while (nl > 0 && localsTypes[nl - 1] == TypeTag.TOP)
  +            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;
           }
  @@ -119,9 +156,14 @@
   
       /**
        * 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;
  +
           CodeIterator ci = ca.iterator();
           ConstPool pool = minfo.getConstPool();
           BasicBlock[] blocks = makeBlocks(ci, 0, ci.getCodeLength(), ca.getExceptionTable(), 0, pool);
  @@ -148,7 +190,9 @@
           ci.begin();
           ci.move(begin);
           ArrayList targets = new ArrayList();
  -        targets.add(new BasicBlock(begin));
  +        BasicBlock bb0 = new BasicBlock(begin);
  +        bb0.inbound = 0;    // the first block is not a branch target.
  +        targets.add(bb0);
           while (ci.hasNext()) {
               int index = ci.next();
               if (index >= end)
  @@ -203,7 +247,9 @@
               }
           }
   
  -        return trimArray(targets, end);
  +        BasicBlock[] blocks = trimArray(targets, end);
  +        markCatch(et, etOffset, blocks);
  +        return blocks;
       }
   
       public int compareTo(Object obj) {
  @@ -253,6 +299,28 @@
           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);
  +            }
  +        }
  +    }
  +
       /**
        * Initializes the first block by the given method descriptor.
        *
  @@ -280,20 +348,18 @@
   
           int n = isStatic ? -1 : 0;
           int i = 1;
  -        do {
               try {
  -                i = descToTag(methodDesc, i, ++n, locals);
  +            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);
               }
  -        } while (i > 0);
   
           numLocals = n;
           localsTypes = locals;
  -        position = 0;
  -        inbound = 0;
       }
   
       private static int descToTag(String desc, int i,
  
  
  
  1.2       +200 -69   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.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- MapMaker.java	10 Apr 2007 16:32:32 -0000	1.1
  +++ MapMaker.java	26 Apr 2007 14:58:16 -0000	1.2
  @@ -22,22 +22,33 @@
    * Stack map maker.
    */
   public class MapMaker extends Tracer {
  -    private boolean moveon;
  +    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 {
  -        if (args.length > 1) {
  +        boolean useMain2 = args[0].equals("0");
  +        if (useMain2 && args.length > 1) {
               main2(args);
               return;
           }
   
  +        for (int i = 0; i < args.length; i++)
  +            main1(args[i]);
  +    }
  +
  +    public static void main1(String className) throws Exception {
           ClassPool cp = ClassPool.getDefault();
  -        javassist.CtClass cc = cp.get(args[0]);
  +        //javassist.CtClass cc = cp.get(className);
  +        javassist.CtClass cc = cp.makeClass(new java.io.FileInputStream(className));
  +        System.out.println(className);
           ClassFile cf = cc.getClassFile();
           java.util.List minfos = cf.getMethods();
           for (int i = 0; i < minfos.size(); i++) {
               MethodInfo minfo = (MethodInfo)minfos.get(i);
               CodeAttribute ca = minfo.getCodeAttribute();
  +            if (ca != null)
               ca.setAttribute(MapMaker.getMap(cp, minfo)); 
           }
   
  @@ -46,19 +57,25 @@
   
       public static void main2(String[] args) throws Exception {
           ClassPool cp = ClassPool.getDefault();
  -        javassist.CtClass cc = cp.get(args[0]);
  +        //javassist.CtClass cc = cp.get(args[1]);
  +        javassist.CtClass cc = cp.makeClass(new java.io.FileInputStream(args[1]));
  +        MethodInfo minfo;
           MapMaker mm;
  -        if (args[1].equals("_init_"))
  -            mm = makeMapMaker(cp, cc.getDeclaredConstructors()[0].getMethodInfo());
  +        if (args[2].equals("_init_"))
  +            // minfo = cc.getDeclaredConstructors()[0].getMethodInfo();
  +            minfo = cc.getClassInitializer().getMethodInfo();
           else
  -            mm = makeMapMaker(cp, cc.getDeclaredMethod(args[1]).getMethodInfo());
  +            minfo = cc.getDeclaredMethod(args[2]).getMethodInfo();
   
  +        mm = makeMapMaker(cp, minfo);
           if (mm == null)
               System.out.println("single basic block");
           else {
               BasicBlock[] blocks = mm.getBlocks();
               for (int i = 0; i < blocks.length; i++)
                   System.out.println(blocks[i]);
  +
  +            StackMapTable smt = mm.toStackMap();
           }
       }
   
  @@ -77,20 +94,25 @@
               return mm.toStackMap();
       }
   
  -    /*
  +    /**
        * Makes basic blocks with stack maps.  If the number of the basic blocks
  -     * is one, this method returns null.
  +     * 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)
           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) 
               return null;
   
           boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
  @@ -102,7 +124,7 @@
                              isStatic, minfo.isConstructor());
           String retType = BasicBlock.getRetType(desc);
           MapMaker mm = new MapMaker(classes, pool, maxStack, maxLocals,
  -                                   blocks, retType, blocks[0]);
  +                                   blocks, retType, blocks[0], 0);
           mm.make(ca.getCode(), et);
           return mm;
       }
  @@ -112,18 +134,21 @@
        */
       MapMaker(ClassPool classes, ConstPool cp,
                       int maxStack, int maxLocals, BasicBlock[] bb,
  -                    String retType, BasicBlock init) {
  -        this(classes, cp, maxStack, maxLocals, bb, retType);
  +             String retType, BasicBlock init, int iterate)
  +    {
  +        this(classes, cp, maxStack, maxLocals, bb, retType, iterate);
           TypeData[] srcTypes = init.localsTypes;
           copyFrom(srcTypes.length, srcTypes, this.localsTypes);
       }
   
       private MapMaker(ClassPool classes, ConstPool cp,
               int maxStack, int maxLocals, BasicBlock[] bb,
  -            String retType)
  +            String retType, int iterateNo)
       {
           super(classes, cp, maxStack, maxLocals, retType);
           blocks = bb;
  +        loopDetected = false;
  +        iteration = iterateNo;
       }
   
       public BasicBlock[] getBlocks() { return blocks; }
  @@ -132,41 +157,18 @@
        * Runs an analyzer.
        */
       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]);
  -        traceExceptions(code, et);
  +        }
  +
           int n = blocks.length;
           for (int i = 0; i < n; i++)
               evalExpected(blocks[i]);
       }
   
  -    private void traceExceptions(byte[] code, ExceptionTable et)
  -        throws BadBytecode
  -    {
  -        int n = et.size();
  -        for (int i = 0; i < n; i++) {
  -            int startPc = et.startPc(i);
  -            int handlerPc = et.handlerPc(i);
  -            BasicBlock handler = BasicBlock.find(blocks, handlerPc);
  -            if (handler.alreadySet())
  -                continue;
  -
  -            BasicBlock thrower = BasicBlock.find(blocks, startPc);
  -            TypeData[] srcTypes = thrower.localsTypes;
  -            copyFrom(srcTypes.length, srcTypes, this.localsTypes);
  -            int typeIndex = et.catchType(i);
  -            String type;
  -            if (typeIndex == 0)
  -                type = "java.lang.Throwable";
  -            else
  -                type = cpool.getClassInfo(typeIndex);
  -
  -            stackTop = 1;
  -            stackTypes[0] = new TypeData.ClassName(type);
  -            recordStackMap(handler);
  -            make(code, handler);
  -        }
  -    }
  -
       // Phase 1: Code Tracing
   
       private void make(byte[] code, BasicBlock bb)
  @@ -174,6 +176,7 @@
       {
           int pos = bb.position;
           int end = pos + bb.length;
  +        traceExceptions(code, bb.catchBlocks);
           moveon = true;
           while (moveon && pos < end)
               pos += doOpcode(pos, code);
  @@ -186,16 +189,55 @@
   
       private void nextBlock(int pos, byte[] code, int offset) throws BadBytecode {
           BasicBlock bb = BasicBlock.find(blocks, pos + offset);
  -        if (bb.alreadySet()) {
  +        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);
  +                                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)
  +        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);
  +            }
  +            else {
  +                recordStackMap(bb, branches.typeIndex);
  +                bb.version = iteration;
  +                MapMaker maker = new MapMaker(classPool, cpool, stackTypes.length,
  +                                   localsTypes.length, blocks, returnType, iteration);
  +
  +                /* the following code is equivalent to maker.copyFrom(this)
  +                 * except stackTypes are not copied.
  +                 */ 
  +                maker.stackTypes[0] = bb.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;
           }
       }
   
  @@ -234,6 +276,9 @@
               TypeData t = srcTypes[i];
               destTypes[i] = t == null ? null : t.getSelf();
               if (t != TOP)
  +                if (t.is2WordType())
  +                    k = i + 1;
  +                else
                   k = i;
           }
   
  @@ -255,12 +300,64 @@
           target.setStackMap(st, tStackTypes, k, tLocalsTypes);
       }
   
  +    private void recordStackMap(BasicBlock 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";
  +        else
  +            type = cpool.getClassInfo(exceptionType);
  +
  +        TypeData[] tStackTypes = new TypeData[stackTypes.length];
  +        tStackTypes[0] = new TypeData.ClassName(type);
  +
  +        target.setStackMap(1, tStackTypes, k, tLocalsTypes);
  +    }
  +
  +    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;
  +
  +        int[] usage = new int[nextUsage.length];
  +        n = usage.length;
  +        for (int i = 0; i < n; i++)
  +            usage[i] = nextUsage[i];
  +
  +        target.localsUsage = usage;
  +    }
  +
  +    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);
  +        }
  +    }
  +
       // Phase 2
   
       void evalExpected(BasicBlock target) throws BadBytecode {
           ClassPool cp = classPool;
           evalExpected(cp, target.stackTop, target.stackTypes);
           TypeData[] types = target.localsTypes;
  +        if (types != null)  // unless this block is dead code
           evalExpected(cp, types.length, types);
       }
   
  @@ -282,13 +379,18 @@
           int n = blocks.length;
           BasicBlock prev = blocks[0];
           int offsetDelta = prev.length;
  +        if (prev.inbound > 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) {
                   bb.resetNumLocals();
                   int diffL = stackMapDiff(prev.numLocals, prev.localsTypes,
                                            bb.numLocals, bb.localsTypes);
  -                toStackMapBody(writer, bb, diffL, offsetDelta);
  +                toStackMapBody(writer, bb, diffL, offsetDelta, prev);
                   offsetDelta = bb.length - 1;
                   prev = bb;
               }
  @@ -301,7 +403,7 @@
       }
   
       private void toStackMapBody(StackMapTable.Writer writer, BasicBlock bb,
  -                                int diffL, int offsetDelta) {
  +                                int diffL, int offsetDelta, BasicBlock prev) {
           // if diffL is -100, two TypeData arrays do not share
           // any elements.
   
  @@ -316,17 +418,16 @@
                   return;
               }
               else if (0 < diffL && diffL <= 3) {
  -                int[] tags = new int[diffL];
                   int[] data = new int[diffL];
  -                fillStackMap(diffL, bb.numLocals - diffL, tags, data,
  +                int[] tags = fillStackMap(bb.numLocals - prev.numLocals,
  +                                          prev.numLocals, data,
                                bb.localsTypes);
                   writer.appendFrame(offsetDelta, tags, data);
                   return;
               }
           }
           else if (stackTop == 1 && diffL == 0) {
  -            TypeData[] types = bb.stackTypes;
  -            TypeData td = types[0];
  +            TypeData td = bb.stackTypes[0];
               if (td == TOP)
                   writer.sameLocals(offsetDelta, StackMapTable.TOP, 0);
               else
  @@ -334,30 +435,45 @@
                                     td.getTypeData(cpool));
               return;
           }
  +        else if (stackTop == 2 && diffL == 0) {
  +            TypeData td = bb.stackTypes[0];
  +            if (td != TOP && td.is2WordType()) {
  +                // bb.stackTypes[1] must be TOP.
  +                writer.sameLocals(offsetDelta, td.getTypeTag(),
  +                                  td.getTypeData(cpool));
  +                return;
  +            }
  +        }
   
  -        int[] stags = new int[stackTop];
           int[] sdata = new int[stackTop];
  -        int nl = bb.numLocals;
  -        int[] ltags = new int[nl];
  -        int[] ldata = new int[nl];
  -        fillStackMap(stackTop, 0, stags, sdata, bb.stackTypes);
  -        fillStackMap(nl, 0, ltags, ldata, bb.localsTypes);
  +        int[] stags = fillStackMap(stackTop, 0, sdata, bb.stackTypes);
  +        int[] ldata = new int[bb.numLocals];
  +        int[] ltags = fillStackMap(bb.numLocals, 0, ldata, bb.localsTypes);
           writer.fullFrame(offsetDelta, ltags, ldata, stags, sdata);
       }
   
  -    private void fillStackMap(int num, int offset, int[] tags, int[] data, TypeData[] types) {
  +    private int[] fillStackMap(int num, int offset, int[] data, TypeData[] types) {
  +        int realNum = diffSize(types, offset, offset + num);
           ConstPool cp = cpool;
  +        int[] tags = new int[realNum];
  +        int j = 0;
           for (int i = 0; i < num; i++) {
               TypeData td = types[offset + i];
               if (td == TOP) {
  -                tags[i] = StackMapTable.TOP;
  -                data[i] = 0;
  +                tags[j] = StackMapTable.TOP;
  +                data[j] = 0;
               }
               else {
  -                tags[i] = td.getTypeTag();
  -                data[i] = td.getTypeData(cp);
  +                tags[j] = td.getTypeTag();
  +                data[j] = td.getTypeData(cp);
  +                if (td.is2WordType())
  +                    i++;
               }
  +
  +            j++;
           }
  +
  +        return tags;
       }
   
       private static int stackMapDiff(int oldTdLen, TypeData[] oldTd,
  @@ -371,7 +487,10 @@
               len = newTdLen;
   
           if (stackMapEq(oldTd, newTd, len))
  -            return diff;
  +            if (diff > 0)
  +                return diffSize(newTd, len, newTdLen);
  +            else
  +                return -diffSize(oldTd, len, oldTdLen);
           else
               return -100;
       }
  @@ -379,7 +498,7 @@
       private static boolean stackMapEq(TypeData[] oldTd, TypeData[] newTd, int len) {
           for (int i = 0; i < len; i++) {
               TypeData td = oldTd[i];
  -            if (td == TOP) {
  +            if (td == TOP) {        // the next element to LONG/DOUBLE is TOP.
                   if (newTd[i] != TOP)
                       return false;
               }
  @@ -391,6 +510,18 @@
           return true;
       }
   
  +    private static int diffSize(TypeData[] types, int offset, int len) {
  +        int num = 0;
  +        while (offset < len) {
  +            TypeData td = types[offset++];
  +            num++;
  +            if (td != TOP && td.is2WordType())
  +                offset++;
  +        }
  +
  +        return num;
  +    }
  +
       // Branch actions
   
       protected void visitBranch(int pos, byte[] code, int offset) throws BadBytecode {
  
  
  
  1.2       +54 -45    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.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- TypeData.java	10 Apr 2007 16:32:32 -0000	1.1
  +++ TypeData.java	26 Apr 2007 14:58:16 -0000	1.2
  @@ -28,38 +28,9 @@
        * array type is a subtype of Cloneable and Serializable 
        */
   
  -    protected ArrayList equivalences;
  -
  -    protected TypeData() {
  -        equivalences = new ArrayList();
  -        equivalences.add(this);
  -    }
  -
  -    public void merge(TypeData neighbor) {
  -        if (this == neighbor)
  -            return;
  +    protected TypeData() {}
   
  -        ArrayList list = equivalences;
  -        ArrayList list2 = neighbor.equivalences;
  -        if (list == list2)
  -            return;
  -
  -        int n = list2.size();
  -        for (int i = 0; i < n; i++) {
  -            TypeData td = (TypeData)list2.get(i);
  -            add(list, td);
  -            td.equivalences = list;
  -        }
  -    }
  -
  -    private static void add(ArrayList list, TypeData td) {
  -        int n = list.size();
  -        for (int i = 0; i < n; i++)
  -            if (list.get(i) == td)
  -                return;
  -
  -        list.add(td);
  -    }
  +    public abstract void merge(TypeData neighbor);
   
       /**
        * Sets the type name of this object type.  If the given type name is
  @@ -69,7 +40,7 @@
        * @param className     dot-separated name unless the type is an array type. 
        */
       static void setType(TypeData td, String className, ClassPool cp) throws BadBytecode {
  -        if (td == null)
  +        if (td == TypeTag.TOP)
               throw new BadBytecode("unset variable");
           else
               td.setType(className, cp);
  @@ -90,14 +61,13 @@
        */
       public abstract TypeData copy();
   
  -    public boolean isBasicType() { return false; }
  -    public boolean isObjectType() { return false; }
  +    public abstract boolean isObjectType();
  +    public boolean is2WordType() { return false; }
       public boolean isNullType() { return false; }
   
       public abstract String getName() throws BadBytecode;
       protected abstract void setType(String s, ClassPool cp) throws BadBytecode;
       public abstract void evalExpectedType(ClassPool cp) throws BadBytecode;
  -    protected abstract boolean hasExpectedType();   // only TypeName can return true.
       public abstract String getExpected() throws BadBytecode;
   
       /**
  @@ -112,6 +82,8 @@
               typeTag = tag;
           }
   
  +        public void merge(TypeData neighbor) {}
  +
           public boolean equals(Object obj) {
               return this == obj;
           }
  @@ -119,7 +91,12 @@
           public int getTypeTag() { return typeTag; }
           public int getTypeData(ConstPool cp) { return 0; }
   
  -        public boolean isBasicType() { return true; }
  +        public boolean isObjectType() { return false; }
  +
  +        public boolean is2WordType() {
  +            return typeTag == StackMapTable.LONG
  +                    || typeTag == StackMapTable.DOUBLE;
  +        }
   
           public TypeData copy() {
               return this;
  @@ -135,10 +112,6 @@
               return name;
           }
   
  -        protected boolean hasExpectedType() {
  -            return false;
  -        }
  -
           protected void setType(String s, ClassPool cp) throws BadBytecode {
               throw new BadBytecode("conflict:" + name + " and " + s);
           }
  @@ -147,16 +120,50 @@
       }
   
       protected static abstract class TypeName extends TypeData {
  +        protected ArrayList equivalences;
  +
           private String expectedName;
           private CtClass cache;
           private boolean evalDone;
   
           protected TypeName() {
  +            equivalences = new ArrayList();
  +            equivalences.add(this);
               expectedName = null;
               cache = null;
               evalDone = false;
           }
   
  +        public void merge(TypeData neighbor) {
  +            if (this == neighbor)
  +                return;
  +
  +            if (!(neighbor instanceof TypeName))
  +                return;     // neighbor might be UninitData
  +
  +            TypeName neighbor2 = (TypeName)neighbor;
  +            ArrayList list = equivalences;
  +            ArrayList list2 = neighbor2.equivalences;
  +            if (list == list2)
  +                return;
  +
  +            int n = list2.size();
  +            for (int i = 0; i < n; i++) {
  +                TypeName tn = (TypeName)list2.get(i);
  +                add(list, tn);
  +                tn.equivalences = list;
  +            }
  +        }
  +
  +        private static void add(ArrayList list, TypeData td) {
  +            int n = list.size();
  +            for (int i = 0; i < n; i++)
  +                if (list.get(i) == td)
  +                    return;
  +
  +            list.add(td);
  +        }
  +
           /* NullType overrides this method.
            */
           public int getTypeTag() { return StackMapTable.OBJECT; }
  @@ -206,7 +213,7 @@
               int n = equiv.size();
               for (int i = 0; i < n; i++) {
                   TypeData td = (TypeData)equiv.get(i);
  -                if (td.hasExpectedType()) {
  +                if (td instanceof TypeName) {
                       TypeName tn = (TypeName)td;
                       if (update(cp, name, tn.expectedName))
                           name = tn.expectedName;
  @@ -218,7 +225,7 @@
   
               for (int i = 0; i < n; i++) {
                   TypeData td = (TypeData)equiv.get(i);
  -                if (td.hasExpectedType()) {
  +                if (td instanceof TypeName) {
                       TypeName tn = (TypeName)td;
                       tn.expectedName = name;
                       tn.cache = null;
  @@ -241,7 +248,7 @@
               return origName;
           }
   
  -        protected boolean hasExpectedType() { return true; }
  +        protected boolean isTypeName() { return true; }
   
           private boolean update(ClassPool cp, String oldName, String typeName) throws BadBytecode {
               if (typeName == null)
  @@ -410,6 +417,8 @@
               this.initialized = false;
           }
   
  +        public void merge(TypeData neighbor) {}
  +
           public int getTypeTag() { return StackMapTable.UNINIT; }
           public int getTypeData(ConstPool cp) { return offset; }
   
  @@ -433,14 +442,14 @@
               return new ClassName(className);
           }
   
  +        public boolean isObjectType() { return true; }
  +
           protected void setType(String typeName, ClassPool cp) throws BadBytecode {
               initialized = true;
           }
   
           public void evalExpectedType(ClassPool cp) throws BadBytecode {}
   
  -        protected boolean hasExpectedType() { return false; }
  -
           public String getName() {
               return className;
           }
  
  
  
  1.2       +24 -7     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.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- Tracer.java	10 Apr 2007 16:32:32 -0000	1.1
  +++ Tracer.java	26 Apr 2007 14:58:16 -0000	1.2
  @@ -36,6 +36,11 @@
       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;
  @@ -44,15 +49,22 @@
           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().
        */
  -    private void readLocal(int reg) {}
  +    protected final void readLocal(int reg) {
  +        if (localsUsage[reg] == UNKNOWN)
  +            localsUsage[reg] = READ;
  +    }
   
  -    private void writeLocal(int reg) {}
  +    protected final void writeLocal(int reg) {
  +        if (localsUsage[reg] == UNKNOWN)
  +            localsUsage[reg] = UPDATED;
  +    }
   
       /**
        * Does abstract interpretation on the given bytecode instruction.
  @@ -230,7 +242,7 @@
           case Opcode.AALOAD : {
               int s = --stackTop - 1;
               TypeData data = stackTypes[s];
  -            if (data == null || data.isBasicType())
  +            if (data == null || !data.isObjectType())
                   throw new BadBytecode("bad AALOAD");
               else
                   stackTypes[s] = new TypeData.ArrayElement(data);
  @@ -278,7 +290,7 @@
   
       private int doXLOAD(int localVar, TypeData type) {
           stackTypes[stackTop++] = type;
  -        if (type == LONG || type == DOUBLE)
  +        if (type.is2WordType())
               stackTypes[stackTop++] = TOP;
   
           readLocal(localVar);
  @@ -414,7 +426,7 @@
           stackTop--;
           writeLocal(index);
           localsTypes[index] = type;
  -        if (type == LONG || type == DOUBLE) {
  +        if (type.is2WordType()) {
               stackTop--;
               localsTypes[index + 1] = TOP;
           }
  @@ -433,7 +445,7 @@
   
       private void doDUP_XX(int delta, int len) {
           TypeData types[] = stackTypes;
  -        int sp = stackTop;
  +        int sp = stackTop - 1;
           int end = sp - len;
           while (sp > end) {
               types[sp + delta] = types[sp];
  @@ -614,8 +626,13 @@
           case Opcode.ANEWARRAY : {
               int i = ByteArray.readU16bit(code, pos + 1);
               String type = cpool.getClassInfo(i).replace('.', '/');
  +            if (type.charAt(0) == '[')
  +                type = "[" + type;
  +            else
  +                type = "[L" + type + ";";
  +
               stackTypes[stackTop - 1]
  -                    = new TypeData.ClassName("[L" + type + ";");
  +                    = new TypeData.ClassName(type);
               return 3; }
           case Opcode.ARRAYLENGTH :
               stackTypes[stackTop - 1] = INTEGER;
  
  
  



More information about the jboss-cvs-commits mailing list