<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
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.
*
* 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
* possible any more.
*
* @param directoryName it must end without a directory separator.
+ * @see #debugWriteFile(String)
*/
public void writeFile(String directoryName)
throws CannotCompileException, IOException
* 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);
}
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);
+ }
+ }
}
}
+ 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.
*
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.
}
}
+ /**
+ * 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.
*/
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;
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) {}