]> source.dussan.org Git - javassist.git/commitdiff
enabled inserting a gap into a large method more than 32KB (related to JIRA 78, 79...
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Fri, 26 Jun 2009 06:50:33 +0000 (06:50 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Fri, 26 Jun 2009 06:50:33 +0000 (06:50 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@482 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

src/main/javassist/CtBehavior.java
src/main/javassist/CtConstructor.java
src/main/javassist/bytecode/CodeAttribute.java
src/main/javassist/bytecode/CodeIterator.java
src/main/javassist/convert/TransformAccessArrayField.java
src/main/javassist/convert/TransformAfter.java
src/main/javassist/convert/TransformBefore.java
src/main/javassist/convert/TransformReadField.java
src/main/javassist/convert/TransformWriteField.java
src/main/javassist/expr/Expr.java

index 528e14b75cb7d6b5930e354bc70c4f177cf0e502..f3677f8d8edf7bc800b53731bb422c86be73149d 100644 (file)
@@ -801,20 +801,30 @@ public abstract class CtBehavior extends CtMember {
         }
     }
 
+    /*
+     * assert subr > pos
+     */
     private void insertGoto(CodeIterator iterator, int subr, int pos)
         throws BadBytecode
     {
+        iterator.setMark(subr);
         // the gap length might be a multiple of 4.
-        boolean wide = subr + 4 - pos > Short.MAX_VALUE;
-        int gapSize = iterator.insertGap(pos, wide ? 4 : 2);
-
+        iterator.writeByte(Opcode.NOP, pos);
+        boolean wide = subr + 2 - pos > Short.MAX_VALUE;
+        pos = iterator.insertGapAt(pos, wide ? 4 : 2, false).position;
+        int offset = iterator.getMark() - pos;
         if (wide) {
             iterator.writeByte(Opcode.GOTO_W, pos);
-            iterator.write32bit(subr - pos + gapSize, pos + 1);
+            iterator.write32bit(offset, pos + 1);
         }
-        else {
+        else if (offset <= Short.MAX_VALUE) {
             iterator.writeByte(Opcode.GOTO, pos);
-            iterator.write16bit(subr - pos + gapSize, pos + 1);
+            iterator.write16bit(offset, pos + 1);
+        }
+        else {
+            pos = iterator.insertGapAt(pos, 2, false).position;
+            iterator.writeByte(Opcode.GOTO_W, pos);
+            iterator.write32bit(iterator.getMark() - pos, pos + 1);
         }
     }
 
@@ -1079,7 +1089,7 @@ public abstract class CtBehavior extends CtMember {
             if (stack > ca.getMaxStack())
                 ca.setMaxStack(stack);
 
-            iterator.insert(index, b.get());
+            index = iterator.insertAt(index, b.get());
             iterator.insert(b.getExceptionTable(), index);
             methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
             return lineNum;
index 831aef4852509d692c9fc49e29baa6a0fa0f3023..a90b73ca2aaa44641b46d85d0df0f8527bd66071 100644 (file)
@@ -379,7 +379,7 @@ public final class CtConstructor extends CtBehavior {
                 String desc = ca.getConstPool().getMethodrefType(mref);
                 int num = Descriptor.numOfParameters(desc) + 1;
                 if (num > 3)
-                    iterator.insertGap(pos, num - 3);
+                    pos = iterator.insertGapAt(pos, num - 3, false).position;
 
                 iterator.writeByte(Opcode.POP, pos++);  // this
                 iterator.writeByte(Opcode.NOP, pos);
index f3ae8a1b9226978ab7c9d9066bfee0080fb51138..34a4fa5b57764de4a65463c9804500e6a44ef2db 100644 (file)
@@ -81,8 +81,6 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
         maxStack = src.getMaxStack();
         maxLocals = src.getMaxLocals();
         exceptions = src.getExceptionTable().copy(cp, classnames);
-        info = src.copyCode(cp, classnames, exceptions, this);
-
         attributes = new LinkedList();
         List src_attr = src.getAttributes();
         int num = src_attr.size();
@@ -90,6 +88,8 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
             AttributeInfo ai = (AttributeInfo)src_attr.get(i);
             attributes.add(ai.copy(cp, classnames));
         }
+
+        info = src.copyCode(cp, classnames, exceptions, this);
     }
 
     CodeAttribute(ConstPool cp, int name_id, DataInputStream in)
@@ -315,7 +315,7 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
     {
         int len = getCodeLength();
         byte[] newCode = new byte[len];
-
+        destCa.info = newCode;
         LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(),
                                 newCode, destCp, classnames);
         return LdcEntry.doit(newCode, ldc, etable, destCa);
@@ -405,13 +405,21 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
                            CodeAttribute ca)
             throws BadBytecode
         {
-            while (ldc != null) {
-                int where = ldc.where;
-                code = CodeIterator.insertGap(code, where, 1, false, etable, ca);
-                code[where] = (byte)Opcode.LDC_W;
-                ByteArray.write16bit(ldc.index, code, where + 1);
-                ldc = ldc.next;
-            }
+            if (ldc != null)
+                code = CodeIterator.changeLdcToLdcW(code, etable, ca, ldc);
+
+            /* The original code was the following:
+
+               while (ldc != null) {
+                 int where = ldc.where;
+                 code = CodeIterator.insertGapCore0(code, where, 1, false, etable, ca);
+                 code[where] = (byte)Opcode.LDC_W;
+                 ByteArray.write16bit(ldc.index, code, where + 1);
+                 ldc = ldc.next;
+               }
+
+               But this code does not support a large method > 32KB.
+            */
 
             return code;
         }
@@ -479,12 +487,12 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
             if (var < 0x100)
                 ci.writeByte(var, index + 1);
             else {
-                int plus = ci.byteAt(index + 2);
-                ci.insertExGap(3);
-                ci.writeByte(WIDE, index);
-                ci.writeByte(IINC, index + 1);
-                ci.write16bit(var, index + 2);
-                ci.write16bit(plus, index + 4);
+                int plus = (byte)ci.byteAt(index + 2);
+                int pos = ci.insertExGap(3);
+                ci.writeByte(WIDE, pos - 3);
+                ci.writeByte(IINC, pos - 2);
+                ci.write16bit(var, pos - 1);
+                ci.write16bit(plus, pos + 1);
             }
         }
         else if (opcode == RET)
@@ -511,10 +519,10 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
         if (var < 0x100)
             ci.writeByte(var, index + 1);
         else {
-            ci.insertExGap(2);
-            ci.writeByte(WIDE, index);
-            ci.writeByte(opcode, index + 1);
-            ci.write16bit(var, index + 2);
+            int pos = ci.insertExGap(2);
+            ci.writeByte(WIDE, pos - 2);
+            ci.writeByte(opcode, pos - 1);
+            ci.write16bit(var, pos);
         }
     }
 
@@ -533,15 +541,15 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
         else {
             opcode = (opcode - opcode_i_0) / 4 + opcode_i;
             if (var < 0x100) {
-                ci.insertExGap(1);
-                ci.writeByte(opcode, index);
-                ci.writeByte(var, index + 1);
+                int pos = ci.insertExGap(1);
+                ci.writeByte(opcode, pos - 1);
+                ci.writeByte(var, pos);
             }
             else {
-                ci.insertExGap(3);
-                ci.writeByte(WIDE, index);
-                ci.writeByte(opcode, index + 1);
-                ci.write16bit(var, index + 2);
+                int pos = ci.insertExGap(3);
+                ci.writeByte(WIDE, pos - 1);
+                ci.writeByte(opcode, pos);
+                ci.write16bit(var, pos + 1);
             }
         }
     }
index f0e45acc31014d8b4e86e95c99946a48839e093e..80507fc08b92dc459e567de55996f5ae31c2bd03 100644 (file)
@@ -15,6 +15,8 @@
 
 package javassist.bytecode;
 
+import java.util.ArrayList;
+
 /**
  * An iterator for editing a code attribute.
  *
@@ -34,6 +36,7 @@ public class CodeIterator implements Opcode {
     protected byte[] bytecode;
     protected int endPos;
     protected int currentPos;
+    protected int mark;
 
     protected CodeIterator(CodeAttribute ca) {
         codeAttr = ca;
@@ -45,7 +48,7 @@ public class CodeIterator implements Opcode {
      * Moves to the first instruction.
      */
     public void begin() {
-        currentPos = 0;
+        currentPos = mark = 0;
         endPos = getCodeLength();
     }
 
@@ -65,6 +68,30 @@ public class CodeIterator implements Opcode {
         currentPos = index;
     }
 
+    /**
+     * Sets a mark to the bytecode at the given index.
+     * The mark can be used to track the position of that bytecode
+     * when code blocks are inserted.
+     * If a code block is inclusively inserted at the position of the
+     * bytecode, the mark is set to the inserted code block.
+     *
+     * @see #getMark()
+     * @since 3.11
+     */
+    public void setMark(int index) {
+        mark = index;
+    }
+
+    /**
+     * Gets the index of the position of the mark set by
+     * <code>setMark</code>.
+     *
+     * @return the index of the position.
+     * @see #setMark(int)
+     * @since 3.11
+     */
+    public int getMark() { return mark; }
+
     /**
      * Returns a Code attribute read with this iterator.
      */
@@ -272,7 +299,7 @@ public class CodeIterator implements Opcode {
      * Inserts the given bytecode sequence
      * before the next instruction that would be returned by
      * <code>next()</code> (not before the instruction returned
-     * by tha last call to <code>next()</code>).
+     * by the last call to <code>next()</code>).
      * Branch offsets and the exception table are also updated.
      *
      * <p>If the next instruction is at the beginning of a block statement,
@@ -289,9 +316,7 @@ public class CodeIterator implements Opcode {
     public int insert(byte[] code)
         throws BadBytecode
     {
-        int pos = currentPos;
-        insert0(currentPos, code, false);
-        return pos;
+        return insert0(currentPos, code, false);
     }
 
     /**
@@ -307,6 +332,11 @@ public class CodeIterator implements Opcode {
      * bytecode sequence for adjusting alignment if the code attribute
      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
      *
+     * <p>The index at which the byte sequence is actually inserted
+     * might be different from pos since some other bytes might be
+     * inserted at other positions (e.g. to change <code>GOTO</code>
+     * to <code>GOTO_W</code>).
+     *
      * @param pos       the index at which a byte sequence is inserted.
      * @param code      inserted bytecode sequence.
      */
@@ -314,6 +344,30 @@ public class CodeIterator implements Opcode {
         insert0(pos, code, false);
     }
 
+    /**
+     * Inserts the given bytecode sequence
+     * before the instruction at the given index <code>pos</code>.
+     * Branch offsets and the exception table are also updated.
+     *
+     * <p>If the instruction at the given index is at the beginning
+     * of a block statement,
+     * then the bytecode is inserted within that block.
+     *
+     * <p>An extra gap may be inserted at the end of the inserted
+     * bytecode sequence for adjusting alignment if the code attribute
+     * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
+     *
+     * @param pos       the index at which a byte sequence is inserted.
+     * @param code      inserted bytecode sequence.
+     * @return          the index indicating the first byte of the
+     *                  inserted byte sequence, which might be
+     *                  different from pos.
+     * @since 3.11
+     */
+    public int insertAt(int pos, byte[] code) throws BadBytecode {
+        return insert0(pos, code, false);
+    }
+
     /**
      * Inserts the given bytecode sequence exclusively
      * before the next instruction that would be returned by
@@ -335,9 +389,7 @@ public class CodeIterator implements Opcode {
     public int insertEx(byte[] code)
         throws BadBytecode
     {
-        int pos = currentPos;
-        insert0(currentPos, code, true);
-        return pos;
+        return insert0(currentPos, code, true);
     }
 
     /**
@@ -353,6 +405,11 @@ public class CodeIterator implements Opcode {
      * bytecode sequence for adjusting alignment if the code attribute
      * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
      *
+     * <p>The index at which the byte sequence is actually inserted
+     * might be different from pos since some other bytes might be
+     * inserted at other positions (e.g. to change <code>GOTO</code>
+     * to <code>GOTO_W</code>). 
+     *
      * @param pos       the index at which a byte sequence is inserted.
      * @param code      inserted bytecode sequence.
      */
@@ -360,16 +417,49 @@ public class CodeIterator implements Opcode {
         insert0(pos, code, true);
     }
 
-    private void insert0(int pos, byte[] code, boolean exclusive)
+    /**
+     * Inserts the given bytecode sequence exclusively
+     * before the instruction at the given index <code>pos</code>.
+     * Branch offsets and the exception table are also updated.
+     *
+     * <p>If the instruction at the given index is at the beginning
+     * of a block statement,
+     * then the bytecode is excluded from that block.
+     *
+     * <p>An extra gap may be inserted at the end of the inserted
+     * bytecode sequence for adjusting alignment if the code attribute
+     * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
+     *
+     * @param pos       the index at which a byte sequence is inserted.
+     * @param code      inserted bytecode sequence.
+     * @return          the index indicating the first byte of the
+     *                  inserted byte sequence, which might be
+     *                  different from pos.
+     * @since 3.11
+     */
+    public int insertExAt(int pos, byte[] code) throws BadBytecode {
+        return insert0(pos, code, true);
+    }
+
+    /**
+     * @return          the index indicating the first byte of the
+     *                  inserted byte sequence.
+     */
+    private int insert0(int pos, byte[] code, boolean exclusive)
         throws BadBytecode
     {
         int len = code.length;
         if (len <= 0)
-            return;
+            return pos;
+
+        // currentPos will change.
+        pos = insertGapAt(pos, len, exclusive).position;
 
-        insertGapCore(pos, len, exclusive);     // currentPos will change.
+        int p = pos;
         for (int j = 0; j < len; ++j)
-            bytecode[pos++] = code[j];
+            bytecode[p++] = code[j];
+
+        return pos;
     }
 
     /**
@@ -388,9 +478,7 @@ public class CodeIterator implements Opcode {
      * @return  the index indicating the first byte of the inserted gap.
      */
     public int insertGap(int length) throws BadBytecode {
-        int pos = currentPos;
-        insertGapCore(currentPos, length, false);
-        return pos;
+        return insertGapAt(currentPos, length, false).position;
     }
 
     /**
@@ -410,14 +498,14 @@ public class CodeIterator implements Opcode {
      *          It might be bigger than <code>length</code>.
      */
     public int insertGap(int pos, int length) throws BadBytecode {
-        return insertGapCore(pos, length, false);
+        return insertGapAt(pos, length, false).length;
     }
 
     /**
      * Inserts an exclusive gap
      * before the next instruction that would be returned by
      * <code>next()</code> (not before the instruction returned
-     * by tha last call to <code>next()</code>).
+     * by the last call to <code>next()</code>).
      * Branch offsets and the exception table are also updated.
      * The inserted gap is filled with NOP.  The gap length may be
      * extended to a multiple of 4.
@@ -429,9 +517,7 @@ public class CodeIterator implements Opcode {
      * @return  the index indicating the first byte of the inserted gap.
      */
     public int insertExGap(int length) throws BadBytecode {
-        int pos = currentPos;
-        insertGapCore(currentPos, length, true);
-        return pos;
+        return insertGapAt(currentPos, length, true).position;
     }
 
     /**
@@ -451,30 +537,101 @@ public class CodeIterator implements Opcode {
      *          It might be bigger than <code>length</code>.
      */
     public int insertExGap(int pos, int length) throws BadBytecode {
-        return insertGapCore(pos, length, true);
+        return insertGapAt(pos, length, true).length;
     }
 
     /**
-     * @return the length of the really inserted gap.
+     * An inserted gap.
+     *
+     * @since 3.11
      */
-    private int insertGapCore(int pos, int length, boolean exclusive)
+    public static class Gap {
+        /**
+         * The position of the gap.
+         */
+        public int position;
+
+        /**
+         * The length of the gap.
+         */
+        public int length;
+    }
+
+    /**
+     * Inserts an inclusive or exclusive gap in front of the instruction
+     * at the given index <code>pos</code>.
+     * Branch offsets and the exception table in the method body
+     * are also updated.  The inserted gap is filled with NOP.
+     * The gap length may be extended to a multiple of 4.
+     *
+     * <p>Suppose that the instruction at the given index is at the
+     * beginning of a block statement.  If the gap is inclusive,
+     * then it is included within that block.  If the gap is exclusive,
+     * then it is excluded from that block.
+     *
+     * <p>The index at which the gap is actually inserted
+     * might be different from pos since some other bytes might be
+     * inserted at other positions (e.g. to change <code>GOTO</code>
+     * to <code>GOTO_W</code>).  The index is available from the <code>Gap</code>
+     * object returned by this method.
+     *
+     * <p>Suppose that the gap is inserted at the position of
+     * the next instruction that would be returned by
+     * <code>next()</code> (not the last instruction returned
+     * by the last call to <code>next()</code>).  The next
+     * instruction returned by <code>next()</code> after the gap is
+     * inserted is still the same instruction.  It is not <code>NOP</code>
+     * at the first byte of the inserted gap.
+     *
+     * @param pos               the index at which a gap is inserted.
+     * @param length            gap length.
+     * @param exclusive         true if exclusive, otherwise false.
+     * @return the position and the length of the inserted gap.
+     * @since 3.11
+     */
+    public Gap insertGapAt(int pos, int length, boolean exclusive)
         throws BadBytecode
     {
-        if (length <= 0)
-            return 0;
+        /**
+         * cursorPos indicates the next bytecode whichever exclusive is
+         * true or false.
+         */
+        Gap gap = new Gap();
+        if (length <= 0) {
+            gap.position = pos;
+            gap.length = 0;
+            return gap;
+        }
 
-        int cur = currentPos;
-        byte[] c = insertGap(bytecode, pos, length, exclusive,
-                             get().getExceptionTable(), codeAttr);
-        int length2 = c.length - bytecode.length;
-        if (cur >= pos)
-            currentPos = cur + length2;
+        byte[] c;
+        int length2;
+        if (bytecode.length + length > Short.MAX_VALUE) {
+            // currentPos might change after calling insertGapCore0w().
+            c = insertGapCore0w(bytecode, pos, length, exclusive,
+                                get().getExceptionTable(), codeAttr, gap);
+            pos = gap.position;
+            length2 = length; // == gap.length
+        }
+        else {
+            int cur = currentPos;
+            c = insertGapCore0(bytecode, pos, length, exclusive,
+                                      get().getExceptionTable(), codeAttr);
+            // insertGapCore0() never changes pos.
+            length2 = c.length - bytecode.length;
+            gap.position = pos;
+            gap.length = length2;
+            if (cur >= pos)
+                currentPos = cur + length2;
+
+            if (mark > pos || (mark == pos && exclusive))
+                mark += length2;
+        }
 
         codeAttr.setCode(c);
         bytecode = c;
         endPos = getCodeLength();
         updateCursors(pos, length2);
-        return length2;
+        return gap;
     }
 
     /**
@@ -619,25 +776,36 @@ public class CodeIterator implements Opcode {
 
     // methods for implementing insertGap().
 
-    /* If "where" is the beginning of a block statement, then the inserted
-     * gap is also included in the block statement.
+    static class AlignmentException extends Exception {}
+
+    /**
+     * insertGapCore0() inserts a gap (some NOPs).
+     * It cannot handle a long code sequence more than 32K.  All branch offsets must be
+     * signed 16bits. 
+     *
+     * If "where" is the beginning of a block statement and exclusive is false,
+     * then the inserted gap is also included in the block statement.
      * "where" must indicate the first byte of an opcode.
      * The inserted gap is filled with NOP.  gapLength may be extended to
      * a multiple of 4.
+     *
+     * This method was also called from CodeAttribute.LdcEntry.doit().
+     *
+     * @param where       It must indicate the first byte of an opcode.
      */
-    static byte[] insertGap(byte[] code, int where, int gapLength,
-                boolean exclusive, ExceptionTable etable, CodeAttribute ca)
+    static byte[] insertGapCore0(byte[] code, int where, int gapLength,
+                                 boolean exclusive, ExceptionTable etable, CodeAttribute ca)
         throws BadBytecode
     {
         if (gapLength <= 0)
             return code;
 
         try {
-            return insertGap0(code, where, gapLength, exclusive, etable, ca);
+            return insertGapCore1(code, where, gapLength, exclusive, etable, ca);
         }
         catch (AlignmentException e) {
             try {
-                return insertGap0(code, where, (gapLength + 3) & ~3,
+                return insertGapCore1(code, where, (gapLength + 3) & ~3,
                                   exclusive, etable, ca);
             }
             catch (AlignmentException e2) {
@@ -646,9 +814,9 @@ public class CodeIterator implements Opcode {
         }
     }
 
-    private static byte[] insertGap0(byte[] code, int where, int gapLength,
-                                boolean exclusive, ExceptionTable etable,
-                                CodeAttribute ca)
+    private static byte[] insertGapCore1(byte[] code, int where, int gapLength,
+                                         boolean exclusive, ExceptionTable etable,
+                                         CodeAttribute ca)
         throws BadBytecode, AlignmentException
     {
         int codeLength = code.length;
@@ -781,6 +949,7 @@ public class CodeIterator implements Opcode {
             }
     }
 
+
     private static int copyGapBytes(byte[] newcode, int j, byte[] code, int i, int iEnd) {
         switch (iEnd - i) {
         case 4:
@@ -804,14 +973,542 @@ public class CodeIterator implements Opcode {
             if (where < target || (exclusive && where == target))
                 offset += gapLength;
         }
+        else if (i == where) {
+            if (target < where && exclusive)
+                offset -= gapLength;
+            else if (where < target && !exclusive)
+                offset += gapLength;
+        }
         else
             if (target < where || (!exclusive && where == target))
                 offset -= gapLength;
 
         return offset;
     }
-}
 
+    static class Pointers {
+        int cursor;
+        int mark0, mark;
+        ExceptionTable etable;
+        LineNumberAttribute line;
+        LocalVariableAttribute vars, types;
+        StackMapTable stack;
+
+        Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca) {
+            cursor = cur;
+            mark = m;
+            mark0 = m0;
+            etable = et;    // non null
+            line = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
+            vars = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.tag);
+            types = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.typeTag);
+            stack = (StackMapTable)ca.getAttribute(StackMapTable.tag);
+        }
+
+        void shiftPc(int where, int gapLength, boolean exclusive) throws BadBytecode {
+            if (where < cursor || (where == cursor && exclusive))
+                cursor += gapLength;
+
+            if (where < mark || (where == mark && exclusive))
+                mark += gapLength;
+
+            if (where < mark0 || (where == mark0 && exclusive))
+                mark0 += gapLength;
+
+            etable.shiftPc(where, gapLength, exclusive);
+            if (line != null)
+                line.shiftPc(where, gapLength, exclusive);
 
-class AlignmentException extends Exception {
+            if (vars != null)
+                vars.shiftPc(where, gapLength, exclusive);
+
+            if (types != null)
+                vars.shiftPc(where, gapLength, exclusive);
+
+            if (stack != null)
+                stack.shiftPc(where, gapLength, exclusive);
+        }
+    }
+
+    /*
+     * This method is called from CodeAttribute.LdcEntry.doit().
+     */
+    static byte[] changeLdcToLdcW(byte[] code, ExceptionTable etable,
+                                  CodeAttribute ca, CodeAttribute.LdcEntry ldcs)
+        throws BadBytecode
+    {
+        ArrayList jumps = makeJumpList(code, code.length);
+        while (ldcs != null) {
+            addLdcW(ldcs, jumps);
+            ldcs = ldcs.next;
+        }
+
+        Pointers pointers = new Pointers(0, 0, 0, etable, ca);
+        byte[] r = insertGap2w(code, 0, 0, false, jumps, pointers);
+        return r;
+    }
+
+    private static void addLdcW(CodeAttribute.LdcEntry ldcs, ArrayList jumps) {
+        int where = ldcs.where;
+        LdcW ldcw = new LdcW(where, ldcs.index);
+        int s = jumps.size();
+        for (int i = 0; i < s; i++)
+            if (where < ((Branch)jumps.get(i)).orgPos) {
+                jumps.add(i, ldcw);
+                return;
+            }
+
+        jumps.add(ldcw);
+    }
+
+    /*
+     * insertGapCore0w() can handle a long code sequence more than 32K. 
+     * It guarantees that the length of the inserted gap (NOPs) is equal to
+     * gapLength.  No other NOPs except some NOPs following TABLESWITCH or
+     * LOOKUPSWITCH will not be inserted. 
+     * 
+     * Note: currentPos might be moved.
+     *
+     * @param where       It must indicate the first byte of an opcode.
+     * @param newWhere    It contains the updated index of the position where a gap
+     *                    is inserted and the length of the gap.
+     *                    It must not be null.
+     */
+    private byte[] insertGapCore0w(byte[] code, int where, int gapLength, boolean exclusive,
+                                   ExceptionTable etable, CodeAttribute ca, Gap newWhere)
+        throws BadBytecode
+    {
+        if (gapLength <= 0)
+            return code;
+
+        ArrayList jumps = makeJumpList(code, code.length);
+        Pointers pointers = new Pointers(currentPos, mark, where, etable, ca);
+        byte[] r = insertGap2w(code, where, gapLength, exclusive, jumps, pointers);
+        currentPos = pointers.cursor;
+        mark = pointers.mark;
+        int where2 = pointers.mark0;
+        if (where2 == currentPos && !exclusive)
+            currentPos += gapLength;
+
+        if (exclusive)
+            where2 -= gapLength;
+
+        newWhere.position = where2;
+        newWhere.length = gapLength;
+        return r;
+    }
+
+    private static byte[] insertGap2w(byte[] code, int where, int gapLength,
+                                      boolean exclusive, ArrayList jumps, Pointers ptrs)
+        throws BadBytecode
+    {
+        int n = jumps.size();
+        if (gapLength > 0) {
+            ptrs.shiftPc(where, gapLength, exclusive);
+            for (int i = 0; i < n; i++)
+                ((Branch)jumps.get(i)).shift(where, gapLength, exclusive);
+        }
+
+        boolean unstable = true;
+        do {
+            while (unstable) {
+                unstable = false;
+                for (int i = 0; i < n; i++) {
+                    Branch b = (Branch)jumps.get(i);
+                    if (b.expanded()) {
+                        unstable = true;
+                        int p = b.pos;
+                        int delta = b.deltaSize();
+                        ptrs.shiftPc(p, delta, false);
+                        for (int j = 0; j < n; j++)
+                            ((Branch)jumps.get(j)).shift(p, delta, false);
+                    }
+                }
+            }
+
+            for (int i = 0; i < n; i++) {
+                Branch b = (Branch)jumps.get(i);
+                int diff = b.gapChanged();
+                if (diff > 0) {
+                    unstable = true;
+                    int p = b.pos;
+                    ptrs.shiftPc(p, diff, false);
+                    for (int j = 0; j < n; j++)
+                        ((Branch)jumps.get(j)).shift(p, diff, false);
+                }
+            }
+        } while (unstable);
+
+        return makeExapndedCode(code, jumps, where, gapLength);
+    }
+
+    private static ArrayList makeJumpList(byte[] code, int endPos)
+        throws BadBytecode
+    {
+        ArrayList jumps = new ArrayList();
+        int nextPos;
+        for (int i = 0; i < endPos; i = nextPos) {
+            nextPos = nextOpcode(code, i);
+            int inst = code[i] & 0xff;
+            // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr
+            if ((153 <= inst && inst <= 168)
+                    || inst == IFNULL || inst == IFNONNULL) {
+                /* 2bytes *signed* offset */
+                int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff);
+                Branch b;
+                if (inst == GOTO || inst == JSR)
+                    b = new Jump16(i, offset);
+                else
+                    b = new If16(i, offset);
+
+                jumps.add(b);
+            }
+            else if (inst == GOTO_W || inst == JSR_W) {
+                /* 4bytes offset */
+                int offset = ByteArray.read32bit(code, i + 1);
+                jumps.add(new Jump32(i, offset));
+            }
+            else if (inst == TABLESWITCH) {
+                int i2 = (i & ~3) + 4;  // 0-3 byte padding
+                int defaultbyte = ByteArray.read32bit(code, i2);
+                int lowbyte = ByteArray.read32bit(code, i2 + 4);
+                int highbyte = ByteArray.read32bit(code, i2 + 8);
+                int i0 = i2 + 12;
+                int size = highbyte - lowbyte + 1;
+                int[] offsets = new int[size];
+                for (int j = 0; j < size; j++) {
+                    offsets[j] = ByteArray.read32bit(code, i0);
+                    i0 += 4;
+                }
+
+                jumps.add(new Table(i, defaultbyte, lowbyte, highbyte, offsets));
+            }
+            else if (inst == LOOKUPSWITCH) {
+                int i2 = (i & ~3) + 4;  // 0-3 byte padding
+                int defaultbyte = ByteArray.read32bit(code, i2);
+                int npairs = ByteArray.read32bit(code, i2 + 4);
+                int i0 = i2 + 8;
+                int[] matches = new int[npairs];
+                int[] offsets = new int[npairs];
+                for (int j = 0; j < npairs; j++) {
+                    matches[j] = ByteArray.read32bit(code, i0);
+                    offsets[j] = ByteArray.read32bit(code, i0 + 4);
+                    i0 += 8;
+                }
+
+                jumps.add(new Lookup(i, defaultbyte, matches, offsets));
+            }
+        }
+
+        return jumps;
+    }
+
+    private static byte[] makeExapndedCode(byte[] code, ArrayList jumps,
+                                           int where, int gapLength)
+        throws BadBytecode
+    {
+        int n = jumps.size();
+        int size = code.length + gapLength;
+        for (int i = 0; i < n; i++) {
+            Branch b = (Branch)jumps.get(i);
+            size += b.deltaSize();
+        }
+
+        byte[] newcode = new byte[size];
+        int src = 0, dest = 0, bindex = 0;
+        int len = code.length;
+        Branch b;
+        int bpos;
+        if (0 < n) {
+            b = (Branch)jumps.get(0);
+            bpos = b.orgPos;
+        }
+        else {
+            b = null;
+            bpos = len;  // src will be never equal to bpos 
+        }
+
+        while (src < len) {
+            if (src == where) {
+                int pos2 = dest + gapLength;
+                while (dest < pos2)
+                    newcode[dest++] = NOP;
+            }
+
+            if (src != bpos)
+                newcode[dest++] = code[src++];
+            else {
+                int s = b.write(src, code, dest, newcode);
+                src += s;
+                dest += s + b.deltaSize();
+                if (++bindex < n) {
+                    b = (Branch)jumps.get(bindex);
+                    bpos = b.orgPos;
+                }
+                else  {
+                    b = null;
+                    bpos = len;
+                }
+            }
+        }
+
+        return newcode;
+    }
+
+    static abstract class Branch {
+        int pos, orgPos;
+        Branch(int p) { pos = orgPos = p; }
+        void shift(int where, int gapLength, boolean exclusive) {
+            if (where < pos || (where == pos && exclusive))
+                pos += gapLength;
+        }
+
+        boolean expanded() { return false; }
+        int gapChanged() { return 0; }
+        int deltaSize() { return 0; }   // newSize - oldSize
+
+        // This returns the original instruction size.
+        abstract int write(int srcPos, byte[] code, int destPos, byte[] newcode);
+    }
+
+    /* used by changeLdcToLdcW() and CodeAttribute.LdcEntry.
+     */
+    static class LdcW extends Branch {
+        int index;
+        boolean state;
+        LdcW(int p, int i) {
+            super(p);
+            index = i;
+            state = true;
+        }
+
+        boolean expanded() {
+            if (state) {
+                state = false;
+                return true;
+            }
+            else
+                return false;
+        }
+
+        int deltaSize() { return 1; }
+
+        int write(int srcPos, byte[] code, int destPos, byte[] newcode) {
+            newcode[destPos] = LDC_W;
+            ByteArray.write16bit(index, newcode, destPos + 1);
+            return 2;
+        }
+    }
+
+    static abstract class Branch16 extends Branch {
+        int offset;
+        int state;
+        static final int BIT16 = 0;
+        static final int EXPAND = 1;
+        static final int BIT32 = 2;
+
+        Branch16(int p, int off) {
+            super(p);
+            offset = off;
+            state = BIT16;
+        }
+
+        void shift(int where, int gapLength, boolean exclusive) {
+            offset = newOffset(pos, offset, where, gapLength, exclusive);
+            super.shift(where, gapLength, exclusive);
+            if (state == BIT16)
+                if (offset < Short.MIN_VALUE || Short.MAX_VALUE < offset)
+                    state = EXPAND;
+        }
+
+        boolean expanded() {
+            if (state == EXPAND) {
+                state = BIT32;
+                return true;
+            }
+            else
+                return false;
+        }
+
+        abstract int deltaSize();
+        abstract void write32(int src, byte[] code, int dest, byte[] newcode);
+
+        int write(int src, byte[] code, int dest, byte[] newcode) {
+            if (state == BIT32)
+                write32(src, code, dest, newcode);
+            else {
+                newcode[dest] = code[src];
+                ByteArray.write16bit(offset, newcode, dest + 1);
+            }
+
+            return 3;
+        }
+    }
+
+    // GOTO or JSR
+    static class Jump16 extends Branch16 {
+        Jump16(int p, int off) {
+            super(p, off);
+        }
+
+        int deltaSize() {
+            return state == BIT32 ? 2 : 0;
+        }
+
+        void write32(int src, byte[] code, int dest, byte[] newcode) {
+            newcode[dest] = (byte)(((code[src] & 0xff) == GOTO) ? GOTO_W : JSR_W);
+            ByteArray.write32bit(offset, newcode, dest + 1);
+        }
+    }
+
+    // if<cond>, if_icmp<cond>, or if_acmp<cond>
+    static class If16 extends Branch16 {
+        If16(int p, int off) {
+            super(p, off);
+        }
+
+        int deltaSize() {
+            return state == BIT32 ? 5 : 0;
+        }
+
+        void write32(int src, byte[] code, int dest, byte[] newcode) {
+            newcode[dest] = (byte)opcode(code[src] & 0xff);
+            newcode[dest + 1] = 0;
+            newcode[dest + 2] = 8;  // branch_offset = 8
+            newcode[dest + 3] = (byte)GOTO_W;
+            ByteArray.write32bit(offset - 3, newcode, dest + 4);
+        }
+
+        int opcode(int op) {
+            if (op == IFNULL)
+                return IFNONNULL;
+            else if (op == IFNONNULL)
+                return IFNULL;
+            else {
+                if (((op - IFEQ) & 1) == 0)
+                    return op + 1;
+                else
+                    return op - 1;
+            }
+        }
+    }
+
+    static class Jump32 extends Branch {
+        int offset;
+
+        Jump32(int p, int off) {
+            super(p);
+            offset = off;
+        }
+
+        void shift(int where, int gapLength, boolean exclusive) {
+            offset = newOffset(pos, offset, where, gapLength, exclusive);
+            super.shift(where, gapLength, exclusive);
+        }
+
+        int write(int src, byte[] code, int dest, byte[] newcode) {
+            newcode[dest] = code[src];
+            ByteArray.write32bit(offset, newcode, dest + 1);
+            return 5;
+        }
+    }
+
+    static abstract class Switcher extends Branch {
+        int gap, defaultByte;
+        int[] offsets;
+
+        Switcher(int pos, int defaultByte, int[] offsets) {
+            super(pos);
+            this.gap = 3 - (pos & 3);
+            this.defaultByte = defaultByte;
+            this.offsets = offsets;
+        }
+
+        void shift(int where, int gapLength, boolean exclusive) {
+            int p = pos;
+            defaultByte = newOffset(p, defaultByte, where, gapLength, exclusive);
+            int num = offsets.length;
+            for (int i = 0; i < num; i++)
+                offsets[i] = newOffset(p, offsets[i], where, gapLength, exclusive);
+
+            super.shift(where, gapLength, exclusive);
+        }
+
+        int gapChanged() {
+            int newGap = 3 - (pos & 3);
+            if (newGap > gap) {
+                int diff = newGap - gap;
+                gap = newGap;
+                return diff;
+            }
+
+            return 0;
+        }
+
+        int deltaSize() {
+            return gap - (3 - (orgPos & 3));
+        }
+
+        int write(int src, byte[] code, int dest, byte[] newcode) {
+            newcode[dest++] = code[src];
+            int padding = 3 - (pos & 3);
+            int nops = gap - padding;
+            while (padding-- > 0)
+                newcode[dest++] = 0;
+
+            ByteArray.write32bit(defaultByte, newcode, dest);
+            int size = write2(dest + 4, newcode);
+            while (nops-- > 0)
+                newcode[dest++] = NOP;
+
+            return 5 + (3 - (orgPos & 3)) + size;
+        }
+
+        abstract int write2(int dest, byte[] newcode);
+    }
+
+    static class Table extends Switcher {
+        int low, high;
+
+        Table(int pos, int defaultByte, int low, int high, int[] offsets) {
+            super(pos, defaultByte, offsets);
+            this.low = low;
+            this.high = high;
+        }
+
+        int write2(int dest, byte[] newcode) {
+            ByteArray.write32bit(low, newcode, dest);
+            ByteArray.write32bit(high, newcode, dest + 4);
+            int n = offsets.length;
+            dest += 8;
+            for (int i = 0; i < n; i++) {
+                ByteArray.write32bit(offsets[i], newcode, dest);
+                dest += 4;
+            }
+
+            return 8 + 4 * n;
+        }
+    }
+
+    static class Lookup extends Switcher {
+        int[] matches;
+
+        Lookup(int pos, int defaultByte, int[] matches, int[] offsets) {
+            super(pos, defaultByte, offsets);
+            this.matches = matches;
+        }
+
+        int write2(int dest, byte[] newcode) {
+            int n = matches.length;
+            ByteArray.write32bit(n, newcode, dest);
+            dest += 4;
+            for (int i = 0; i < n; i++) {
+                ByteArray.write32bit(matches[i], newcode, dest);
+                ByteArray.write32bit(offsets[i], newcode, dest + 4);
+                dest += 8;
+            }
+
+            return 4 + 8 * n;
+        }
+    }
 }
index 959f818493d8100bd8f156c98b534e121075d0fe..f70148f473ed39ec4f340e2be1946a5e838160cf 100644 (file)
@@ -32,7 +32,7 @@ import javassist.bytecode.analysis.Frame;
  *
  * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
  * @author Jason T. Greene
- * @version $Revision: 1.7 $
+ * @version $Revision: 1.8 $
  */
 public final class TransformAccessArrayField extends Transformer {
     private final String methodClassname;
@@ -142,8 +142,9 @@ public final class TransformAccessArrayField extends Transformer {
             // The gap may include extra padding
             // Write a nop in case the padding pushes the instruction forward
             iterator.writeByte(NOP, pos);
-            int gapLength = iterator.insertGap(pos, castType != null ? 5 : 2);
-
+            CodeIterator.Gap gap
+                = iterator.insertGapAt(pos, castType != null ? 5 : 2, false);
+            pos = gap.position;
             int mi = cp.addClassInfo(methodClassname);
             int methodref = cp.addMethodrefInfo(mi, methodName, signature);
             iterator.writeByte(INVOKESTATIC, pos);
@@ -155,7 +156,7 @@ public final class TransformAccessArrayField extends Transformer {
                 iterator.write16bit(index, pos + 4);
             }
 
-            pos = updatePos(pos, gapLength);
+            pos = updatePos(pos, gap.length);
         }
 
         return pos;
index 1ab05d0df3f3ceed74bd13dab3518bc12ce6a307..601511586f6171ba52ec48b48a5cb36083a5d3cc 100644 (file)
@@ -32,8 +32,10 @@ public class TransformAfter extends TransformBefore {
         iterator.insert(saveCode);
         iterator.insert(loadCode);
         int p = iterator.insertGap(3);
+        iterator.setMark(p);
         iterator.insert(loadCode);
         pos = iterator.next();
+        p = iterator.getMark();
         iterator.writeByte(iterator.byteAt(pos), p);
         iterator.write16bit(iterator.u16bitAt(pos + 1), p + 1);
         iterator.writeByte(INVOKESTATIC, pos);
index f42c90053f7a712bbfe0332444472545f42ac110..2ad585f5dc5491da6170ab6b41af46da76890fb7 100644 (file)
@@ -31,6 +31,10 @@ public class TransformBefore extends TransformCall {
         throws NotFoundException
     {
         super(next, origMethod, beforeMethod);
+
+        // override
+        methodDescriptor = origMethod.getMethodInfo2().getDescriptor();
+
         parameterTypes = origMethod.getParameterTypes();
         locals = 0;
         maxLocals = 0;
index 073b80f43ee4b5d8a03eddfb00640d04a0604102..a9e613c26781cdafc9e26ca026b08eef17ecdc6a 100644 (file)
@@ -76,7 +76,7 @@ public class TransformReadField extends Transformer {
             if (typedesc != null) {
                 if (c == GETSTATIC) {
                     iterator.move(pos);
-                    iterator.insertGap(1); // insertGap() may insert 4 bytes.
+                    pos = iterator.insertGap(1); // insertGap() may insert 4 bytes.
                     iterator.writeByte(ACONST_NULL, pos);
                     pos = iterator.next();
                 }
index e2a284f7ff638409a5e3b9af11d9d4492e9dcaf5..2b6f8bb547a31cdea5b3c992b55b1afa54252de2 100644 (file)
@@ -41,7 +41,7 @@ final public class TransformWriteField extends TransformReadField {
                     char c0 = typedesc.charAt(0);
                     if (c0 == 'J' || c0 == 'D') {       // long or double
                         // insertGap() may insert 4 bytes.
-                        iterator.insertGap(3);
+                        pos = iterator.insertGap(3);
                         iterator.writeByte(ACONST_NULL, pos);
                         iterator.writeByte(DUP_X2, pos + 1);
                         iterator.writeByte(POP, pos + 2);
@@ -49,7 +49,7 @@ final public class TransformWriteField extends TransformReadField {
                     }
                     else {
                         // insertGap() may insert 4 bytes.
-                        iterator.insertGap(2);
+                        pos = iterator.insertGap(2);
                         iterator.writeByte(ACONST_NULL, pos);
                         iterator.writeByte(SWAP, pos + 1);
                         ca.setMaxStack(ca.getMaxStack() + 1);
index 0092cc215bbe8dfaf5883189a3da596bc5e3ad22..56d9edd3d2ec0f6b3448a0038e3402aa39b96faf 100644 (file)
@@ -295,7 +295,7 @@ public abstract class Expr implements Opcode {
             iterator.writeByte(NOP, pos + i);
 
         if (gap > 0)
-            iterator.insertGap(pos, gap);
+            pos = iterator.insertGapAt(pos, gap, false).position;
 
         iterator.write(code, pos);
         iterator.insert(bytecode.getExceptionTable(), pos);