]> source.dussan.org Git - javassist.git/commitdiff
fixed JASSIST-47 and 60.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 1 May 2008 10:47:59 +0000 (10:47 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 1 May 2008 10:47:59 +0000 (10:47 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@435 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

Readme.html
src/main/javassist/CtBehavior.java
src/main/javassist/CtClass.java
src/main/javassist/bytecode/CodeAttribute.java
src/main/javassist/bytecode/Descriptor.java
src/main/javassist/bytecode/LocalVariableAttribute.java
src/main/javassist/bytecode/StackMapTable.java
src/main/javassist/compiler/MemberResolver.java

index 84d606ae18969756e1585134d527789afdd68392..b19a0101049756feaae0cd4a425b33eb6fca2678 100644 (file)
@@ -283,7 +283,7 @@ see javassist.Dump.
 
 <p>-version 3.7.2
 <ul>
-       <li>JASSIST-51 was fixed.
+       <li>JASSIST-45, 47, 51, 54-57, 60 were fixed.
 </ul>
 
 <p>-version 3.7.1 on March 10, 2008
index 6fb9361ad93ac50823d257411c76d2b0543851e9..3539fd5fa79fc5c85a86f87d791e35ae8bcc7b09 100644 (file)
@@ -519,6 +519,74 @@ public abstract class CtBehavior extends CtMember {
         ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc));
     }
 
+    /**
+     * Inserts a new parameter, which becomes the first parameter.
+     */
+    public void insertParameter(CtClass type)
+        throws CannotCompileException
+    {
+        declaringClass.checkModify();
+        String desc = methodInfo.getDescriptor();
+        String desc2 = Descriptor.insertParameter(type, desc);
+        try {
+            addParameter2(Modifier.isStatic(getModifiers()) ? 0 : 1, type, desc);
+        }
+        catch (BadBytecode e) {
+            throw new CannotCompileException(e);
+        }
+
+        methodInfo.setDescriptor(desc2);
+    }
+
+    /**
+     * Appends a new parameter, which becomes the last parameter.
+     */
+    public void addParameter(CtClass type)
+        throws CannotCompileException
+    {
+        declaringClass.checkModify();
+        String desc = methodInfo.getDescriptor();
+        String desc2 = Descriptor.appendParameter(type, desc);
+        int offset = Modifier.isStatic(getModifiers()) ? 0 : 1;
+        try {
+            addParameter2(offset + Descriptor.paramSize(desc), type, desc);
+        }
+        catch (BadBytecode e) {
+            throw new CannotCompileException(e);
+        }
+
+        methodInfo.setDescriptor(desc2);
+    }
+
+    private void addParameter2(int where, CtClass type, String desc)
+        throws BadBytecode
+    {
+        CodeAttribute ca = methodInfo.getCodeAttribute();
+        if (ca != null) {
+            int size = 1;
+            char typeDesc = 'L';
+            int classInfo = 0;
+            if (type.isPrimitive()) {
+                CtPrimitiveType cpt = (CtPrimitiveType)type;
+                size = cpt.getDataSize();
+                typeDesc = cpt.getDescriptor();
+            }
+            else
+                classInfo = methodInfo.getConstPool().addClassInfo(type);
+
+            ca.insertLocalVar(where, size);
+            LocalVariableAttribute va
+                            = (LocalVariableAttribute)
+                              ca.getAttribute(LocalVariableAttribute.tag);
+            if (va != null)
+                va.shiftIndex(where, size);
+
+            StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag);
+            if (smt != null)
+                smt.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo);
+        }
+    }
+
     /**
      * Modifies the method/constructor body.
      *
index 463518192bbdfd9d8aec1ac05757c10c1bf6b89f..313a761846bb276a9ae9cd7295b3c7149baeea76 100644 (file)
@@ -1216,6 +1216,8 @@ public abstract class CtClass {
      * object in the current directory.
      * Once this method is called, further modifications are not
      * possible any more.
+     *
+     * @see #debugWriteFile()
      */
     public void writeFile()
         throws NotFoundException, IOException, CannotCompileException
@@ -1230,6 +1232,7 @@ public abstract class CtClass {
      * possible any more.
      *
      * @param directoryName     it must end without a directory separator.
+     * @see #debugWriteFile(String)
      */
     public void writeFile(String directoryName)
         throws CannotCompileException, IOException
@@ -1263,9 +1266,22 @@ public abstract class CtClass {
      * This method would be useful for debugging.
      */
     public void debugWriteFile() {
+        debugWriteFile(".");
+    }
+
+    /**
+     * Writes a class file as <code>writeFile()</code> does although this
+     * method does not prune or freeze the class after writing the class
+     * file.  Note that, once <code>writeFile()</code> or <code>toBytecode()</code>
+     * is called, it cannot be called again since the class is pruned and frozen.
+     * This method would be useful for debugging.
+     *
+     * @param directoryName     it must end without a directory separator.
+     */
+    public void debugWriteFile(String directoryName) {
         try {
             boolean p = stopPruning(true);
-            writeFile();
+            writeFile(directoryName);
             defrost();
             stopPruning(p);
         }
index 35ab7ddd64843373fc932c0f698a9049a69c7a12..f3ae8a1b9226978ab7c9d9066bfee0080fb51138 100644 (file)
@@ -395,25 +395,154 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
         newcode[i] = (byte)(index >> 8);
         newcode[i + 1] = (byte)index;
     }
-}
 
-final class LdcEntry {
-    LdcEntry next;
-    int where;
-    int index;
+    static class LdcEntry {
+        LdcEntry next;
+        int where;
+        int index;
+
+        static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable,
+                           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;
+            }
 
-    static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable,
-                       CodeAttribute ca)
-        throws BadBytecode
+            return code;
+        }
+    }
+
+    /**
+     * Changes the index numbers of the local variables
+     * to append a new parameter.
+     * This method does not update <code>LocalVariableAttribute</code>
+     * or <code>StackMapTable</code>.  These attributes must be
+     * explicitly updated.
+     *
+     * @param where         the index of the new parameter.
+     * @param size         the type size of the new parameter (1 or 2).
+     *
+     * @see LocalVariableAttribute#shiftIndex(int, int)
+     * @see StackMapTable#insertLocal(int, int, int)
+     */
+    public void insertLocalVar(int where, int size) throws BadBytecode {
+        CodeIterator ci = iterator();
+        while (ci.hasNext())
+            shiftIndex(ci, where, size);
+
+        setMaxLocals(getMaxLocals() + size);
+    }
+
+    /**
+     * @param lessThan      If the index of the local variable is
+     *                      less than this value, it does not change.
+     *                      Otherwise, the index is increased.
+     * @param delta         the indexes of the local variables are
+     *                      increased by this value.
+     */
+    private static void shiftIndex(CodeIterator ci, int lessThan, int delta) throws BadBytecode {
+        int index = ci.next();
+        int opcode = ci.byteAt(index);
+        if (opcode < ILOAD)
+            return;
+        else if (opcode < IASTORE) {
+            if (opcode < ILOAD_0) {
+                // iload, lload, fload, dload, aload
+                shiftIndex8(ci, index, opcode, lessThan, delta);
+            }
+            else if (opcode < IALOAD) {
+                // iload_0, ..., aload_3
+                shiftIndex0(ci, index, opcode, lessThan, delta, ILOAD_0, ILOAD);
+            }
+            else if (opcode < ISTORE)
+                return;
+            else if (opcode < ISTORE_0) {
+                // istore, lstore, ...
+                shiftIndex8(ci, index, opcode, lessThan, delta);
+            }
+            else {
+                // istore_0, ..., astore_3
+                shiftIndex0(ci, index, opcode, lessThan, delta, ISTORE_0, ISTORE);
+            }
+        }
+        else if (opcode == IINC) {
+            int var = ci.byteAt(index + 1);
+            if (var < lessThan)
+                return;
+
+            var += delta;
+            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);
+            }
+        }
+        else if (opcode == RET)
+            shiftIndex8(ci, index, opcode, lessThan, delta);
+        else if (opcode == WIDE) {
+            int var = ci.u16bitAt(index + 2);
+            if (var < lessThan)
+                return;
+
+            var += delta;
+            ci.write16bit(var, index + 2);
+        }
+    }
+
+    private static void shiftIndex8(CodeIterator ci, int index, int opcode,
+                                    int lessThan, int delta)
+         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;
+        int var = ci.byteAt(index + 1);
+        if (var < lessThan)
+            return;
+
+        var += delta;
+        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);
         }
+    }
 
-        return code;
+    private static void shiftIndex0(CodeIterator ci, int index, int opcode,
+                                    int lessThan, int delta,
+                                    int opcode_i_0, int opcode_i)
+        throws BadBytecode
+    {
+        int var = (opcode - opcode_i_0) % 4;
+        if (var < lessThan)
+            return;
+
+        var += delta;
+        if (var < 4)
+            ci.writeByte(opcode + delta, index);
+        else {
+            opcode = (opcode - opcode_i_0) / 4 + opcode_i;
+            if (var < 0x100) {
+                ci.insertExGap(1);
+                ci.writeByte(opcode, index);
+                ci.writeByte(var, index + 1);
+            }
+            else {
+                ci.insertExGap(3);
+                ci.writeByte(WIDE, index);
+                ci.writeByte(opcode, index + 1);
+                ci.write16bit(var, index + 2);
+            }
+        }
     }
 }
index d40f238059bff2658250cabe711382e8ece67603..d9db92baa53bc64d9b41dfba2e2520740745b889 100644 (file)
@@ -352,6 +352,43 @@ public class Descriptor {
                    + desc.substring(1);
     }
 
+    /**
+     * Appends a parameter type to the parameter list represented
+     * by the given descriptor.  The appended parameter becomes
+     * the last parameter.
+     *
+     * @param type      the type of the appended parameter.
+     * @param desc      descriptor
+     */
+    public static String appendParameter(CtClass type, String descriptor) {
+        int i = descriptor.indexOf(')');
+        if (i < 0)
+            return descriptor;
+        else {
+            StringBuffer newdesc = new StringBuffer();
+            newdesc.append(descriptor.substring(0, i));
+            toDescriptor(newdesc, type);
+            newdesc.append(descriptor.substring(i));
+            return newdesc.toString();
+        }
+    }
+
+    /**
+     * Inserts a parameter type at the beginning of the parameter
+     * list represented
+     * by the given descriptor.
+     *
+     * @param type              the type of the inserted parameter.
+     * @param descriptor        the descriptor of the method.
+     */
+    public static String insertParameter(CtClass type,
+                                         String descriptor) {
+        if (descriptor.charAt(0) != '(')
+            return descriptor;
+        else
+            return "(" + of(type) + descriptor.substring(1);
+    }
+
     /**
      * Changes the return type included in the given descriptor.
      *
index 549291374beb6e68f2c3c87b76003d0d7e1afe42..80f96533ae226aa06b7c55ac6fe8879b4e886efd 100644 (file)
@@ -91,6 +91,22 @@ public class LocalVariableAttribute extends AttributeInfo {
         info = newInfo;
     }
 
+    /**
+     * For each <code>local_variable_table[i].index</code>,
+     * this method increases <code>index</code> by <code>delta</code>.
+     *
+     * @param lessThan      the index does not change if it
+     *                      is less than this value.
+     */
+    public void shiftIndex(int lessThan, int delta) {
+        int size = info.length;
+        for (int i = 2; i < size; i += 10){
+            int org = ByteArray.readU16bit(info, i + 8);
+            if (org >= lessThan)
+                ByteArray.write16bit(org + delta, info, i + 8);
+        }
+    }
+
     /**
      * Returns <code>local_variable_table_length</code>.
      * This represents the number of entries in the table.
index f1704dc42c722c9ac97f7eda5fe4ba86eaae37d6..2ca8bd72529f181eaa18f9b08625d6b3aa6902cd 100644 (file)
@@ -424,6 +424,94 @@ public class StackMapTable extends AttributeInfo {
         }
     }
 
+    /**
+     * Updates this stack map table when a new local variable is added.
+     *
+     * @param index          the index of the added local variable.
+     * @param tag            the type tag of that local variable. 
+     * @param classInfo      the index of the <code>CONSTANT_Class_info</code> structure
+     *                       in a constant pool table.  This should be zero unless the tag
+     *                       is <code>ITEM_Object</code>.
+     *
+     * @see #typeTagOf(char)
+     * @see ConstPool
+     */
+    public void insertLocal(int index, int tag, int classInfo)
+        throws BadBytecode
+    {
+        byte[] data = new InsertLocal(this.get(), index, tag, classInfo).doit();
+        this.set(data);
+    }
+
+    /**
+     * Returns the tag of the type specified by the
+     * descriptor.  This method returns <code>INTEGER</code>
+     * unless the descriptor is either D (double), F (float),
+     * J (long), L (class type), or [ (array).
+     *
+     * @param descriptor        the type descriptor.
+     * @see Descriptor
+     */
+    public static int typeTagOf(char descriptor) {
+        switch (descriptor) {
+        case 'D' :
+            return DOUBLE;
+        case 'F' :
+            return FLOAT;
+        case 'J' :
+            return LONG;
+        case 'L' :
+        case '[' :
+            return OBJECT;
+        // case 'V' :
+        default :
+            return INTEGER;
+        }
+    }
+
+    static class InsertLocal extends SimpleCopy {
+        private int varIndex;
+        private int varTag, varData;
+
+        public InsertLocal(byte[] data, int varIndex, int varTag, int varData) {
+            super(data);
+            this.varIndex = varIndex;
+            this.varTag = varTag;
+            this.varData = varData;
+        }
+
+        public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
+                              int[] stackTags, int[] stackData) {
+            int len = localTags.length;
+            if (len < varIndex) {
+                super.fullFrame(pos, offsetDelta, localTags, localData, stackTags, stackData);
+                return;
+            }
+
+            int typeSize = (varTag == LONG || varTag == DOUBLE) ? 2 : 1;
+            int[] localTags2 = new int[len + typeSize];
+            int[] localData2 = new int[len + typeSize];
+            int index = varIndex;
+            int j = 0;
+            for (int i = 0; i < len; i++) {
+                if (j == index)
+                    j += typeSize;
+
+                localTags2[j] = localTags[i];
+                localData2[j++] = localData[i];
+            }
+
+            localTags2[index] = varTag;
+            localData2[index] = varData;
+            if (typeSize > 1) {
+                localTags2[index + 1] = TOP;
+                localData2[index + 1] = 0;
+            }
+
+            super.fullFrame(pos, offsetDelta, localTags2, localData2, stackTags, stackData);
+        }
+    }
+
     /**
      * A writer of stack map tables.
      */
index d263e1b083f81f5b4002734e57fdd5baf199fce2..858a235c0adcc38a28c35914e976810578099971 100644 (file)
@@ -129,19 +129,23 @@ public class MemberResolver implements TokenId {
         else
             onlyExact = maybe != null;
 
+        int mod = clazz.getModifiers();
+        boolean isIntf = Modifier.isInterface(mod);
         try {
-            CtClass pclazz = clazz.getSuperclass();
-            if (pclazz != null) {
-                Method r = lookupMethod(pclazz, methodName, argTypes,
-                                        argDims, argClassNames, onlyExact);
-                if (r != null)
-                    return r;
+            // skip searching java.lang.Object if clazz is an interface type.
+            if (!isIntf) {
+                CtClass pclazz = clazz.getSuperclass();
+                if (pclazz != null) {
+                    Method r = lookupMethod(pclazz, methodName, argTypes,
+                                            argDims, argClassNames, onlyExact);
+                    if (r != null)
+                        return r;
+                }
             }
         }
         catch (NotFoundException e) {}
 
-        int mod = clazz.getModifiers();
-        if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
+        if (isIntf || Modifier.isAbstract(mod))
             try {
                 CtClass[] ifs = clazz.getInterfaces();
                 int size = ifs.length;
@@ -152,6 +156,17 @@ public class MemberResolver implements TokenId {
                     if (r != null)
                         return r;
                 }
+
+                if (isIntf) {
+                    // finally search java.lang.Object.
+                    CtClass pclazz = clazz.getSuperclass();
+                    if (pclazz != null) {
+                        Method r = lookupMethod(pclazz, methodName, argTypes,
+                                                argDims, argClassNames, onlyExact);
+                        if (r != null)
+                            return r;
+                    }
+                }
             }
             catch (NotFoundException e) {}