From e7a87072d7ef60f89569ce88dfa318373463fc63 Mon Sep 17 00:00:00 2001 From: aclement Date: Wed, 9 Sep 2009 22:18:20 +0000 Subject: [PATCH] refactoring --- .../org/aspectj/apache/bcel/Repository.java | 49 +- .../apache/bcel/classfile/JavaClass.java | 48 +- .../apache/bcel/classfile/Utility.java | 1962 +++++++++-------- .../aspectj/apache/bcel/generic/ClassGen.java | 1249 ++++++----- .../bcel/generic/FieldGenOrMethodGen.java | 30 +- .../apache/bcel/generic/ReferenceType.java | 6 +- .../aspectj/apache/bcel/util/ClassQueue.java | 81 - .../aspectj/apache/bcel/util/ClassVector.java | 79 - 8 files changed, 1730 insertions(+), 1774 deletions(-) delete mode 100644 bcel-builder/src/org/aspectj/apache/bcel/util/ClassQueue.java delete mode 100644 bcel-builder/src/org/aspectj/apache/bcel/util/ClassVector.java diff --git a/bcel-builder/src/org/aspectj/apache/bcel/Repository.java b/bcel-builder/src/org/aspectj/apache/bcel/Repository.java index 32832f90e..073355b5b 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/Repository.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/Repository.java @@ -67,7 +67,7 @@ import org.aspectj.apache.bcel.util.SyntheticRepository; * @see org.aspectj.apache.bcel.util.Repository * @see org.aspectj.apache.bcel.util.SyntheticRepository * - * @version $Id: Repository.java,v 1.5 2008/08/28 15:36:59 aclement Exp $ + * @version $Id: Repository.java,v 1.6 2009/09/09 22:18:20 aclement Exp $ * @author M. Dahm */ public abstract class Repository { @@ -166,29 +166,30 @@ public abstract class Repository { // getRepository().removeClass(clazz); // } - /** - * @return list of super classes of clazz in ascending order, i.e., Object is always the last element - */ - public static JavaClass[] getSuperClasses(JavaClass clazz) { - return clazz.getSuperClasses(); - } - - /** - * @return list of super classes of clazz in ascending order, i.e., Object is always the last element. return "null", if class - * cannot be found. - */ - public static JavaClass[] getSuperClasses(String class_name) { - JavaClass jc = lookupClass(class_name); - return jc == null ? null : getSuperClasses(jc); - } - - /** - * @return all interfaces implemented by class and its super classes and the interfaces that those interfaces extend, and so on. - * (Some people call this a transitive hull). - */ - public static JavaClass[] getInterfaces(JavaClass clazz) { - return clazz.getAllInterfaces(); - } + // /** + // * @return list of super classes of clazz in ascending order, i.e., Object is always the last element + // */ + // public static JavaClass[] getSuperClasses(JavaClass clazz) { + // return clazz.getSuperClasses(); + // } + // + // /** + // * @return list of super classes of clazz in ascending order, i.e., Object is always the last element. return "null", if class + // * cannot be found. + // */ + // public static JavaClass[] getSuperClasses(String class_name) { + // JavaClass jc = lookupClass(class_name); + // return jc == null ? null : getSuperClasses(jc); + // } + // + // /** + // * @return all interfaces implemented by class and its super classes and the interfaces that those interfaces extend, and so + // on. + // * (Some people call this a transitive hull). + // */ + // public static JavaClass[] getInterfaces(JavaClass clazz) { + // return clazz.getAllInterfaces(); + // } // /** // * @return all interfaces implemented by class and its super classes and the interfaces that extend those interfaces, and so diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java index ac3fae655..0d62fb573 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java @@ -61,15 +61,16 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; import java.util.List; +import java.util.Queue; import java.util.StringTokenizer; import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations; import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.apache.bcel.util.ClassQueue; -import org.aspectj.apache.bcel.util.ClassVector; import org.aspectj.apache.bcel.util.SyntheticRepository; /** @@ -79,7 +80,7 @@ import org.aspectj.apache.bcel.util.SyntheticRepository; * The intent of this class is to represent a parsed or otherwise existing class file. Those interested in programatically * generating classes should see the ClassGen class. * - * @version $Id: JavaClass.java,v 1.16 2009/09/09 21:26:54 aclement Exp $ + * @version $Id: JavaClass.java,v 1.17 2009/09/09 22:18:20 aclement Exp $ * @see org.aspectj.apache.bcel.generic.ClassGen * @author M. Dahm */ @@ -789,13 +790,18 @@ public class JavaClass extends Modifiers implements Cloneable, Node { return true; } - JavaClass[] super_interfaces = getAllInterfaces(); + Collection superInterfaces = getAllInterfaces(); - for (int i = 0; i < super_interfaces.length; i++) { - if (super_interfaces[i].equals(inter)) { + for (JavaClass superInterface : superInterfaces) { + if (superInterface.equals(inter)) { return true; } } + // for (int i = 0; i < super_interfaces.length; i++) { + // if (super_interfaces[i].equals(inter)) { + // return true; + // } + // } return false; } @@ -821,13 +827,11 @@ public class JavaClass extends Modifiers implements Cloneable, Node { */ public JavaClass[] getSuperClasses() { JavaClass clazz = this; - ClassVector vec = new ClassVector(); - + List vec = new ArrayList(); for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) { - vec.addElement(clazz); + vec.add(clazz); } - - return vec.toArray(); + return vec.toArray(new JavaClass[vec.size()]); } /** @@ -852,33 +856,33 @@ public class JavaClass extends Modifiers implements Cloneable, Node { /** * Get all interfaces implemented by this JavaClass (transitively). */ - // OPTIMIZE get rid of ClassQueue and ClassVector - public JavaClass[] getAllInterfaces() { - ClassQueue queue = new ClassQueue(); - ClassVector vec = new ClassVector(); + public Collection getAllInterfaces() { + Queue queue = new LinkedList(); + List interfaceList = new ArrayList(); - queue.enqueue(this); + queue.add(this); - while (!queue.empty()) { - JavaClass clazz = queue.dequeue(); + while (!queue.isEmpty()) { + JavaClass clazz = queue.remove(); JavaClass souper = clazz.getSuperClass(); JavaClass[] interfaces = clazz.getInterfaces(); if (clazz.isInterface()) { - vec.addElement(clazz); + interfaceList.add(clazz); } else { if (souper != null) { - queue.enqueue(souper); + queue.add(souper); } } for (int i = 0; i < interfaces.length; i++) { - queue.enqueue(interfaces[i]); + queue.add(interfaces[i]); } } - return vec.toArray(); + return interfaceList; + // return interfaceList.toArray(new JavaClass[interfaceList.size()]); } /** diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java index f8770affe..b121d803b 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java @@ -58,6 +58,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -73,966 +74,1019 @@ import org.aspectj.apache.bcel.util.ByteSequence; /** * Utility functions that do not really belong to any class in particular. - * - * @version $Id: Utility.java,v 1.8 2009/09/09 19:56:20 aclement Exp $ - * @author M. Dahm * - * modified: Andy Clement 2-mar-05 Removed unnecessary static and optimized + * @version $Id: Utility.java,v 1.9 2009/09/09 22:18:20 aclement Exp $ + * @author M. Dahm + * + * modified: Andy Clement 2-mar-05 Removed unnecessary static and optimized */ public abstract class Utility { - /* The 'WIDE' instruction is used in the byte code to allow 16-bit wide indices for local - * variables. This opcode precedes an 'ILOAD', e.g.. The opcode immediately following takes - * an extra byte which is combined with the following byte to form a 16-bit value. - */ - private static boolean wide = false; - - /** - * Convert bit field of flags into string such as 'static final'. - * - * @param access_flags Access flags - * @return String representation of flags - */ - public static final String accessToString(int access_flags) { - return accessToString(access_flags, false); - } - - /** - * Convert bit field of flags into string such as 'static final'. - * - * Special case: Classes compiled with new compilers and with the - * 'ACC_SUPER' flag would be said to be "synchronized". This is - * because SUN used the same value for the flags 'ACC_SUPER' and - * 'ACC_SYNCHRONIZED'. - * - * @param access_flags Access flags - * @param for_class access flags are for class qualifiers ? - * @return String representation of flags - */ - public static final String accessToString(int access_flags, boolean for_class) { - StringBuffer buf = new StringBuffer(); - - int p = 0; - for (int i=0; p < Constants.MAX_ACC_FLAG; i++) { // Loop through known flags - p = pow2(i); - if ((access_flags & p) != 0) { - // Special case: see comment at top of class... - if (for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE))) - continue; - buf.append(Constants.ACCESS_NAMES[i]).append(" "); - } - } - return buf.toString().trim(); - } - - - /** - * @return "class" or "interface", depending on the ACC_INTERFACE flag - */ - public static final String classOrInterface(int access_flags) { - return ((access_flags & Constants.ACC_INTERFACE) != 0)? "interface" : "class"; - } - - - /** - * Disassemble a byte array of JVM byte codes starting from code line - * 'index' and return the disassembled string representation. Decode only - * 'num' opcodes (including their operands), use -1 if you want to - * decompile everything. - * - * @param code byte code array - * @param constant_pool Array of constants - * @param index offset in `code' array - * (number of opcodes, not bytes!) - * @param length number of opcodes to decompile, -1 for all - * @param verbose be verbose, e.g. print constant pool index - * @return String representation of byte codes - */ - public static final String codeToString(byte[] code, - ConstantPool constant_pool, - int index, int length, boolean verbose) - { - StringBuffer buf = new StringBuffer(code.length * 20); // Should be sufficient - ByteSequence stream = new ByteSequence(code); - - try { - for (int i=0; i < index; i++) // Skip `index' lines of code - codeToString(stream, constant_pool, verbose); - - for (int i=0; stream.available() > 0; i++) { - if ((length < 0) || (i < length)) { - String indices = fillup(stream.getIndex() + ":", 6, true, ' '); - buf.append(indices + codeToString(stream, constant_pool, verbose) + '\n'); - } - } - } catch(IOException e) { - System.out.println(buf.toString()); - e.printStackTrace(); - throw new ClassFormatException("Byte code error: " + e); - } - - return buf.toString(); - } - - - - /** - * Disassemble a stream of byte codes and return the - * string representation. - */ - public static final String codeToString(byte[] code, ConstantPool constant_pool, int index, int length) { - return codeToString(code, constant_pool, index, length, true); - } - - - - public static final String codeToString(ByteSequence bytes, ConstantPool constant_pool) - throws IOException { - return codeToString(bytes, constant_pool, true); - } - - /** - * Shorten long class names, java/lang/String becomes String. - * - * @param str The long class name - * @return Compacted class name - */ - public static final String compactClassName(String str) { - return compactClassName(str, true); - } - - /** - * Shorten long class name str, i.e., chop off the prefix, - * if the - * class name starts with this string and the flag chopit is true. - * Slashes / are converted to dots .. - * - * @param str The long class name - * @param prefix The prefix the get rid off - * @param chopit Flag that determines whether chopping is executed or not - * @return Compacted class name - */ - public static final String compactClassName(String str, - String prefix, - boolean chopit) - { - int len = prefix.length(); - - str = str.replace('/', '.'); // Is '/' on all systems, even DOS - - if (chopit) { - // If string starts with 'prefix' and contains no further dots - if (str.startsWith(prefix)) { - String result = str.substring(len); - if ( result.indexOf('.') == -1) { - str = result; - } - } - } - return str; - } - - - - /** - * Shorten long class names, java/lang/String becomes - * java.lang.String, - * e.g.. If chopit is true the prefix java.lang - * is also removed. - * - * @param str The long class name - * @param chopit Flag that determines whether chopping is executed or not - * @return Compacted class name - */ - public static final String compactClassName(String str, boolean chopit) { - return compactClassName(str, "java.lang.", chopit); - } - - public static final String methodSignatureToString(String signature,String name,String access) { - return methodSignatureToString(signature, name, access, true); - } - - public static final String methodSignatureToString(String signature,String name, - String access,boolean chopit) { - return methodSignatureToString(signature, name, access, chopit, null); - } - - /** - * This method converts such a string into a Java type declaration like - * 'void main(String[])' and throws a 'ClassFormatException' when the parsed - * type is invalid. - * - * @param signature Method signature - * @param name Method name - * @param access Method access rights - * @return Java type declaration - * @throws ClassFormatException - */ - public static final String methodSignatureToString(String signature, String name, - String access, boolean chopit, LocalVariableTable vars) throws ClassFormatException { -// -// -// if (signature.charAt(0)!='(') -// throw new ClassFormatException("Invalid method signature: " + signature); -// -// // Break the signature into two pieces: ([PARAMS])[RETURNTYPE] -// int lastBracketPos = signature.lastIndexOf(")"); -// String parameters = signature.substring(1,lastBracketPos); -// String returnType = signature.substring(lastBracketPos+1); -// -// // e.g. parameters="Ljava/util/List;" -// // returnType="V" -// -// // Break signature into its parts -// // dont want lots of substringing so lets use an index -// int posn=0; -// StringBuffer piece; -// while (posn= 0)? 0 : 1; - - try { // Read all declarations between for `(' and `)' - if (signature.charAt(0) != '(') - throw new ClassFormatException("Invalid method signature: " + signature); - - index = 1; // current string position - - while(signature.charAt(index) != ')') { - ResultHolder rh = signatureToStringInternal(signature.substring(index), chopit); - String param_type = rh.getResult(); - buf.append(param_type); - - if(vars != null) { - LocalVariable l = vars.getLocalVariable(var_index); - - if(l != null) - buf.append(" " + l.getName()); - } else - buf.append(" arg" + var_index); - - if("double".equals(param_type) || "long".equals(param_type)) - var_index += 2; - else - var_index++; - - buf.append(", "); - index += rh.getConsumedChars(); - } - - index++; - - // Read return type after `)' - type = signatureToString(signature.substring(index), chopit); - - } catch(StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid method signature: " + signature); - } - - if(buf.length() > 1) // Tack off the extra ", " - buf.setLength(buf.length() - 2); - - buf.append(")"); - - return access + ((access.length() > 0)? " " : "") + // May be an empty string - type + " " + name + buf.toString(); - } - - - - /** - * Replace all occurences of old in str with new. - * - * @param str String to permute - * @param old String to be replaced - * @param new Replacement string - * @return new String object - */ - public static final String replace(String str, String old, String new_) { - int index, old_index; - StringBuffer buf = new StringBuffer(); - - try { - index = str.indexOf(old); - if ( index != -1) { - old_index = 0; - - // While we have something to replace - while((index = str.indexOf(old, old_index)) != -1) { - buf.append(str.substring(old_index, index)); // append prefix - buf.append(new_); // append replacement - old_index = index + old.length(); // Skip 'old'.length chars - } - - buf.append(str.substring(old_index)); // append rest of string - str = buf.toString(); - } - } catch(StringIndexOutOfBoundsException e) { - System.err.println(e); - } - - return str; - } - - /** - * Converts signature to string with all class names compacted. - * - * @param signature to convert - * @return Human readable signature - */ - public static final String signatureToString(String signature) { - return signatureToString(signature, true); - } - - - public static final String signatureToString(String signature,boolean chopit) { - ResultHolder rh = signatureToStringInternal(signature,chopit); - return rh.getResult(); - } - - /** - * This method converts this string into a Java type declaration such as - * 'String[]' and throws a `ClassFormatException' when the parsed type is - * invalid. - * - * @param signature Class signature - * @param chopit Flag that determines whether chopping is executed or not - * @return Java type declaration - */ - public static final ResultHolder signatureToStringInternal(String signature,boolean chopit) { - int processedChars = 1; // This is the default, read just one char - try { - switch(signature.charAt(0)) { - case 'B' : return ResultHolder.BYTE; - case 'C' : return ResultHolder.CHAR; - case 'D' : return ResultHolder.DOUBLE; - case 'F' : return ResultHolder.FLOAT; - case 'I' : return ResultHolder.INT; - case 'J' : return ResultHolder.LONG; - - case 'L' : { // Full class name - int index = signature.indexOf(';'); // Look for closing `;' - // Jump to the correct ';' - if (index!=-1 && - signature.length()>index+1 && - signature.charAt(index+1)=='>') index = index+2; - - if (index < 0) - throw new ClassFormatException("Invalid signature: " + signature); - - int genericStart = signature.indexOf('<'); - int genericEnd = signature.indexOf('>'); - if (genericStart !=-1) { - // FIXME asc going to need a lot more work in here for generics - ResultHolder rh = signatureToStringInternal(signature.substring(genericStart+1,genericEnd),chopit); - ResultHolder retval = new ResultHolder(compactClassName(signature.substring(1,genericStart)+"<"+ - rh.getResult()+">",chopit),genericEnd+1); - return retval; - } else { - processedChars = index + 1; // "Lblabla;" `L' and `;' are removed - ResultHolder retval = new ResultHolder(compactClassName(signature.substring(1, index), chopit),processedChars); - return retval; - } - } - - case 'S' : return ResultHolder.SHORT; - case 'Z' : return ResultHolder.BOOLEAN; - - case '[' : { // Array declaration - StringBuffer brackets; - int consumedChars,n; - - brackets = new StringBuffer(); // Accumulate []'s - // Count opening brackets and look for optional size argument - for(n=0; signature.charAt(n) == '['; n++) - brackets.append("[]"); - consumedChars = n; - // The rest of the string denotes a `' - ResultHolder restOfIt = signatureToStringInternal(signature.substring(n),chopit); - - // type = signatureToString(signature.substring(n), chopit); - - consumedChars+= restOfIt.getConsumedChars(); - return new ResultHolder(restOfIt.getResult() + brackets.toString(),consumedChars); - } - - case 'V' : return ResultHolder.VOID; - - default : throw new ClassFormatException("Invalid signature: `" + - signature + "'"); - } - } catch(StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid signature: " + e + ":" + signature); - } - } - - - - - /** - * Return type of method signature as a byte value as defined in Constants - * - * @param signature in format described above - * @return type of method signature - * @see Constants - */ - public static final byte typeOfMethodSignature(String signature) throws ClassFormatException { - int index; - - try { - if (signature.charAt(0) != '(') - throw new ClassFormatException("Invalid method signature: " + signature); - index = signature.lastIndexOf(')') + 1; - return typeOfSignature(signature.substring(index)); - } catch(StringIndexOutOfBoundsException e) { - throw new ClassFormatException("Invalid method signature: " + signature); - } - } - - /** - * Convert (signed) byte to (unsigned) short value, i.e., all negative - * values become positive. - */ - private static final short byteToShort(byte b) { - return (b < 0)? (short)(256 + b) : (short)b; - } - - /** - * Convert bytes into hexidecimal string - * - * @return bytes as hexidecimal string, e.g. 00 FA 12 ... - */ - public static final String toHexString(byte[] bytes) { - StringBuffer buf = new StringBuffer(); - - for(int i=0; i < bytes.length; i++) { - short b = byteToShort(bytes[i]); - String hex = Integer.toString(b, 0x10); - - // Just one digit, so prepend 0 - if (b < 0x10) buf.append('0'); - - buf.append(hex); - - if (i < bytes.length - 1) buf.append(' '); - } - - return buf.toString(); - } - - /** - * Return a string for an integer justified left or right and filled up with - * 'fill' characters if necessary. - * - * @param i integer to format - * @param length length of desired string - * @param left_justify format left or right - * @param fill fill character - * @return formatted int - */ - public static final String format(int i, int length, boolean left_justify, char fill) { - return fillup(Integer.toString(i), length, left_justify, fill); - } - - /** - * Fillup char with up to length characters with char `fill' and justify it left or right. - * - * @param str string to format - * @param length length of desired string - * @param left_justify format left or right - * @param fill fill character - * @return formatted string - */ - public static final String fillup(String str, int length, boolean left_justify, char fill) { - int len = length - str.length(); - char[] buf = new char[(len < 0)? 0 : len]; - - for(int j=0; j < buf.length; j++) - buf[j] = fill; - - if(left_justify) - return str + new String(buf); - else - return new String(buf) + str; - } - - /** - * Escape all occurences of newline chars '\n', quotes \", etc. - */ - public static final String convertString(String label) { - char[] ch = label.toCharArray(); - StringBuffer buf = new StringBuffer(); - - for(int i=0; i < ch.length; i++) { - switch(ch[i]) { - case '\n': - buf.append("\\n"); break; - case '\r': - buf.append("\\r"); break; - case '\"': - buf.append("\\\""); break; - case '\'': - buf.append("\\'"); break; - case '\\': - buf.append("\\\\"); break; - default: - buf.append(ch[i]); break; - } - } - - return buf.toString(); - } - - /** - * Converts a list of AnnotationGen objects into a set of attributes - * that can be attached to the class file. - * - * @param cp The constant pool gen where we can create the necessary name refs - * @param vec A list of AnnotationGen objects - */ - public static Attribute[] getAnnotationAttributes(ConstantPool cp,List vec) { - - if (vec.size()==0) return null; - - try { - int countVisible = 0; - int countInvisible = 0; - - // put the annotations in the right output stream - for (int i=0; i2) rvaIndex = cp.addUtf8("RuntimeVisibleAnnotations"); - if (riaData.length>2) riaIndex = cp.addUtf8("RuntimeInvisibleAnnotations"); - - List newAttributes = new ArrayList(); - if (rvaData.length>2) { - newAttributes.add( - new RuntimeVisibleAnnotations(rvaIndex,rvaData.length,rvaData,cp)); - } - if (riaData.length>2) { - newAttributes.add( - new RuntimeInvisibleAnnotations(riaIndex,riaData.length,riaData,cp)); - } - - return newAttributes.toArray(new Attribute[]{}); - } catch (IOException e) { - System.err.println("IOException whilst processing annotations"); - e.printStackTrace(); + /* + * The 'WIDE' instruction is used in the byte code to allow 16-bit wide indices for local variables. This opcode precedes an + * 'ILOAD', e.g.. The opcode immediately following takes an extra byte which is combined with the following byte to form a + * 16-bit value. + */ + private static boolean wide = false; + + /** + * Convert bit field of flags into string such as 'static final'. + * + * @param access_flags Access flags + * @return String representation of flags + */ + public static final String accessToString(int access_flags) { + return accessToString(access_flags, false); + } + + /** + * Convert bit field of flags into string such as 'static final'. + * + * Special case: Classes compiled with new compilers and with the 'ACC_SUPER' flag would be said to be "synchronized". This is + * because SUN used the same value for the flags 'ACC_SUPER' and 'ACC_SYNCHRONIZED'. + * + * @param access_flags Access flags + * @param for_class access flags are for class qualifiers ? + * @return String representation of flags + */ + public static final String accessToString(int access_flags, boolean for_class) { + StringBuffer buf = new StringBuffer(); + + int p = 0; + for (int i = 0; p < Constants.MAX_ACC_FLAG; i++) { // Loop through known flags + p = pow2(i); + if ((access_flags & p) != 0) { + // Special case: see comment at top of class... + if (for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE))) + continue; + buf.append(Constants.ACCESS_NAMES[i]).append(" "); + } + } + return buf.toString().trim(); + } + + /** + * @return "class" or "interface", depending on the ACC_INTERFACE flag + */ + public static final String classOrInterface(int access_flags) { + return ((access_flags & Constants.ACC_INTERFACE) != 0) ? "interface" : "class"; } - return null; - } - - /** - * Annotations against a class are stored in one of four attribute kinds: - * - RuntimeVisibleParameterAnnotations - * - RuntimeInvisibleParameterAnnotations - */ - // OPTIMIZE looks heavyweight? - public static Attribute[] getParameterAnnotationAttributes(ConstantPool cp,List[] /*Array of lists, array size depends on #params */ vec) { - - int visCount[] = new int[vec.length]; - int totalVisCount = 0; - int invisCount[] = new int[vec.length]; - int totalInvisCount = 0; - try { - - for (int i=0; i0) { - List l = vec[i]; - for (Iterator iter = l.iterator(); iter.hasNext();) { - AnnotationGen element = (AnnotationGen) iter.next(); - if (element.isRuntimeVisible()) element.dump(rvaDos); + + /** + * Disassemble a byte array of JVM byte codes starting from code line 'index' and return the disassembled string representation. + * Decode only 'num' opcodes (including their operands), use -1 if you want to decompile everything. + * + * @param code byte code array + * @param constant_pool Array of constants + * @param index offset in `code' array (number of opcodes, not bytes!) + * @param length number of opcodes to decompile, -1 for all + * @param verbose be verbose, e.g. print constant pool index + * @return String representation of byte codes + */ + public static final String codeToString(byte[] code, ConstantPool constant_pool, int index, int length, boolean verbose) { + StringBuffer buf = new StringBuffer(code.length * 20); // Should be sufficient + ByteSequence stream = new ByteSequence(code); + + try { + for (int i = 0; i < index; i++) + // Skip `index' lines of code + codeToString(stream, constant_pool, verbose); + + for (int i = 0; stream.available() > 0; i++) { + if ((length < 0) || (i < length)) { + String indices = fillup(stream.getIndex() + ":", 6, true, ' '); + buf.append(indices + codeToString(stream, constant_pool, verbose) + '\n'); } - } - } - rvaDos.close(); - - // Lets do the invisible ones - ByteArrayOutputStream riaBytes = new ByteArrayOutputStream(); - DataOutputStream riaDos = new DataOutputStream(riaBytes); - riaDos.writeByte(vec.length); // First goes number of parameters - - for (int i=0; i0) { - List l = vec[i]; - for (Iterator iter = l.iterator(); iter.hasNext();) { - AnnotationGen element = (AnnotationGen) iter.next(); - if (!element.isRuntimeVisible()) element.dump(riaDos); + } + } catch (IOException e) { + System.out.println(buf.toString()); + e.printStackTrace(); + throw new ClassFormatException("Byte code error: " + e); + } + + return buf.toString(); + } + + /** + * Disassemble a stream of byte codes and return the string representation. + */ + public static final String codeToString(byte[] code, ConstantPool constant_pool, int index, int length) { + return codeToString(code, constant_pool, index, length, true); + } + + public static final String codeToString(ByteSequence bytes, ConstantPool constant_pool) throws IOException { + return codeToString(bytes, constant_pool, true); + } + + /** + * Shorten long class names, java/lang/String becomes String. + * + * @param str The long class name + * @return Compacted class name + */ + public static final String compactClassName(String str) { + return compactClassName(str, true); + } + + /** + * Shorten long class name str, i.e., chop off the prefix, if the class name starts with this string and the + * flag chopit is true. Slashes / are converted to dots .. + * + * @param str The long class name + * @param prefix The prefix the get rid off + * @param chopit Flag that determines whether chopping is executed or not + * @return Compacted class name + */ + public static final String compactClassName(String str, String prefix, boolean chopit) { + int len = prefix.length(); + + str = str.replace('/', '.'); // Is '/' on all systems, even DOS + + if (chopit) { + // If string starts with 'prefix' and contains no further dots + if (str.startsWith(prefix)) { + String result = str.substring(len); + if (result.indexOf('.') == -1) { + str = result; } - } - } - riaDos.close(); - - byte[] rvaData = rvaBytes.toByteArray(); - byte[] riaData = riaBytes.toByteArray(); - - int rvaIndex = -1; - int riaIndex = -1; - - if (totalVisCount>0) rvaIndex = cp.addUtf8("RuntimeVisibleParameterAnnotations"); - if (totalInvisCount>0) riaIndex = cp.addUtf8("RuntimeInvisibleParameterAnnotations"); - - List newAttributes = new ArrayList(); - - if (totalVisCount>0) { - newAttributes.add( - new RuntimeVisibleParameterAnnotations(rvaIndex,rvaData.length,rvaData,cp)); - } - - - if (totalInvisCount>0) { - newAttributes.add( - new RuntimeInvisibleParameterAnnotations(riaIndex,riaData.length,riaData,cp)); - } - - return newAttributes.toArray(new Attribute[]{}); - } catch (IOException e) { - System.err.println("IOException whilst processing parameter annotations"); - e.printStackTrace(); + } + } + return str; + } + + /** + * Shorten long class names, java/lang/String becomes java.lang.String, e.g.. If chopit is + * true the prefix java.lang is also removed. + * + * @param str The long class name + * @param chopit Flag that determines whether chopping is executed or not + * @return Compacted class name + */ + public static final String compactClassName(String str, boolean chopit) { + return compactClassName(str, "java.lang.", chopit); + } + + public static final String methodSignatureToString(String signature, String name, String access) { + return methodSignatureToString(signature, name, access, true); + } + + public static final String methodSignatureToString(String signature, String name, String access, boolean chopit) { + return methodSignatureToString(signature, name, access, chopit, null); + } + + /** + * This method converts such a string into a Java type declaration like 'void main(String[])' and throws a + * 'ClassFormatException' when the parsed type is invalid. + * + * @param signature Method signature + * @param name Method name + * @param access Method access rights + * @return Java type declaration + * @throws ClassFormatException + */ + public static final String methodSignatureToString(String signature, String name, String access, boolean chopit, + LocalVariableTable vars) throws ClassFormatException { + // + // + // if (signature.charAt(0)!='(') + // throw new ClassFormatException("Invalid method signature: " + signature); + // + // // Break the signature into two pieces: ([PARAMS])[RETURNTYPE] + // int lastBracketPos = signature.lastIndexOf(")"); + // String parameters = signature.substring(1,lastBracketPos); + // String returnType = signature.substring(lastBracketPos+1); + // + // // e.g. parameters="Ljava/util/List;" + // // returnType="V" + // + // // Break signature into its parts + // // dont want lots of substringing so lets use an index + // int posn=0; + // StringBuffer piece; + // while (posn= 0) ? 0 : 1; + + try { // Read all declarations between for `(' and `)' + if (signature.charAt(0) != '(') + throw new ClassFormatException("Invalid method signature: " + signature); + + index = 1; // current string position + + while (signature.charAt(index) != ')') { + ResultHolder rh = signatureToStringInternal(signature.substring(index), chopit); + String param_type = rh.getResult(); + buf.append(param_type); + + if (vars != null) { + LocalVariable l = vars.getLocalVariable(var_index); + + if (l != null) + buf.append(" " + l.getName()); + } else + buf.append(" arg" + var_index); + + if ("double".equals(param_type) || "long".equals(param_type)) + var_index += 2; + else + var_index++; + + buf.append(", "); + index += rh.getConsumedChars(); + } + + index++; + + // Read return type after `)' + type = signatureToString(signature.substring(index), chopit); + + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid method signature: " + signature); + } + + if (buf.length() > 1) // Tack off the extra ", " + buf.setLength(buf.length() - 2); + + buf.append(")"); + + return access + ((access.length() > 0) ? " " : "") + // May be an empty string + type + " " + name + buf.toString(); + } + + /** + * Replace all occurences of old in str with new. + * + * @param str String to permute + * @param old String to be replaced + * @param new Replacement string + * @return new String object + */ + public static final String replace(String str, String old, String new_) { + int index, old_index; + StringBuffer buf = new StringBuffer(); + + try { + index = str.indexOf(old); + if (index != -1) { + old_index = 0; + + // While we have something to replace + while ((index = str.indexOf(old, old_index)) != -1) { + buf.append(str.substring(old_index, index)); // append prefix + buf.append(new_); // append replacement + old_index = index + old.length(); // Skip 'old'.length chars + } + + buf.append(str.substring(old_index)); // append rest of string + str = buf.toString(); + } + } catch (StringIndexOutOfBoundsException e) { + System.err.println(e); + } + + return str; + } + + /** + * Converts signature to string with all class names compacted. + * + * @param signature to convert + * @return Human readable signature + */ + public static final String signatureToString(String signature) { + return signatureToString(signature, true); + } + + public static final String signatureToString(String signature, boolean chopit) { + ResultHolder rh = signatureToStringInternal(signature, chopit); + return rh.getResult(); + } + + /** + * This method converts this string into a Java type declaration such as 'String[]' and throws a `ClassFormatException' when the + * parsed type is invalid. + * + * @param signature Class signature + * @param chopit Flag that determines whether chopping is executed or not + * @return Java type declaration + */ + public static final ResultHolder signatureToStringInternal(String signature, boolean chopit) { + int processedChars = 1; // This is the default, read just one char + try { + switch (signature.charAt(0)) { + case 'B': + return ResultHolder.BYTE; + case 'C': + return ResultHolder.CHAR; + case 'D': + return ResultHolder.DOUBLE; + case 'F': + return ResultHolder.FLOAT; + case 'I': + return ResultHolder.INT; + case 'J': + return ResultHolder.LONG; + + case 'L': { // Full class name + int index = signature.indexOf(';'); // Look for closing `;' + // Jump to the correct ';' + if (index != -1 && signature.length() > index + 1 && signature.charAt(index + 1) == '>') + index = index + 2; + + if (index < 0) + throw new ClassFormatException("Invalid signature: " + signature); + + int genericStart = signature.indexOf('<'); + int genericEnd = signature.indexOf('>'); + if (genericStart != -1) { + // FIXME asc going to need a lot more work in here for generics + ResultHolder rh = signatureToStringInternal(signature.substring(genericStart + 1, genericEnd), chopit); + ResultHolder retval = new ResultHolder(compactClassName(signature.substring(1, genericStart) + "<" + + rh.getResult() + ">", chopit), genericEnd + 1); + return retval; + } else { + processedChars = index + 1; // "Lblabla;" `L' and `;' are removed + ResultHolder retval = new ResultHolder(compactClassName(signature.substring(1, index), chopit), processedChars); + return retval; + } + } + + case 'S': + return ResultHolder.SHORT; + case 'Z': + return ResultHolder.BOOLEAN; + + case '[': { // Array declaration + StringBuffer brackets; + int consumedChars, n; + + brackets = new StringBuffer(); // Accumulate []'s + // Count opening brackets and look for optional size argument + for (n = 0; signature.charAt(n) == '['; n++) + brackets.append("[]"); + consumedChars = n; + // The rest of the string denotes a `' + ResultHolder restOfIt = signatureToStringInternal(signature.substring(n), chopit); + + // type = signatureToString(signature.substring(n), chopit); + + consumedChars += restOfIt.getConsumedChars(); + return new ResultHolder(restOfIt.getResult() + brackets.toString(), consumedChars); + } + + case 'V': + return ResultHolder.VOID; + + default: + throw new ClassFormatException("Invalid signature: `" + signature + "'"); + } + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new ClassFormatException("Invalid signature: " + e + ":" + signature); + } + } + + /** + * Return type of method signature as a byte value as defined in Constants + * + * @param signature in format described above + * @return type of method signature + * @see Constants + */ + public static final byte typeOfMethodSignature(String signature) throws ClassFormatException { + int index; + + try { + if (signature.charAt(0) != '(') + throw new ClassFormatException("Invalid method signature: " + signature); + index = signature.lastIndexOf(')') + 1; + return typeOfSignature(signature.substring(index)); + } catch (StringIndexOutOfBoundsException e) { + throw new ClassFormatException("Invalid method signature: " + signature); + } + } + + /** + * Convert (signed) byte to (unsigned) short value, i.e., all negative values become positive. + */ + private static final short byteToShort(byte b) { + return (b < 0) ? (short) (256 + b) : (short) b; + } + + /** + * Convert bytes into hexidecimal string + * + * @return bytes as hexidecimal string, e.g. 00 FA 12 ... + */ + public static final String toHexString(byte[] bytes) { + StringBuffer buf = new StringBuffer(); + + for (int i = 0; i < bytes.length; i++) { + short b = byteToShort(bytes[i]); + String hex = Integer.toString(b, 0x10); + + // Just one digit, so prepend 0 + if (b < 0x10) + buf.append('0'); + + buf.append(hex); + + if (i < bytes.length - 1) + buf.append(' '); + } + + return buf.toString(); + } + + /** + * Return a string for an integer justified left or right and filled up with 'fill' characters if necessary. + * + * @param i integer to format + * @param length length of desired string + * @param left_justify format left or right + * @param fill fill character + * @return formatted int + */ + public static final String format(int i, int length, boolean left_justify, char fill) { + return fillup(Integer.toString(i), length, left_justify, fill); + } + + /** + * Fillup char with up to length characters with char `fill' and justify it left or right. + * + * @param str string to format + * @param length length of desired string + * @param left_justify format left or right + * @param fill fill character + * @return formatted string + */ + public static final String fillup(String str, int length, boolean left_justify, char fill) { + int len = length - str.length(); + char[] buf = new char[(len < 0) ? 0 : len]; + + for (int j = 0; j < buf.length; j++) + buf[j] = fill; + + if (left_justify) + return str + new String(buf); + else + return new String(buf) + str; + } + + /** + * Escape all occurences of newline chars '\n', quotes \", etc. + */ + public static final String convertString(String label) { + char[] ch = label.toCharArray(); + StringBuffer buf = new StringBuffer(); + + for (int i = 0; i < ch.length; i++) { + switch (ch[i]) { + case '\n': + buf.append("\\n"); + break; + case '\r': + buf.append("\\r"); + break; + case '\"': + buf.append("\\\""); + break; + case '\'': + buf.append("\\'"); + break; + case '\\': + buf.append("\\\\"); + break; + default: + buf.append(ch[i]); + break; + } + } + + return buf.toString(); + } + + /** + * Converts a list of AnnotationGen objects into a set of attributes that can be attached to the class file. + * + * @param cp The constant pool gen where we can create the necessary name refs + * @param vec A list of AnnotationGen objects + */ + public static Collection getAnnotationAttributes(ConstantPool cp, List vec) { + + if (vec.size() == 0) + return null; + + try { + int countVisible = 0; + int countInvisible = 0; + + // put the annotations in the right output stream + for (int i = 0; i < vec.size(); i++) { + AnnotationGen a = vec.get(i); + if (a.isRuntimeVisible()) + countVisible++; + else + countInvisible++; + } + + ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream(); + ByteArrayOutputStream riaBytes = new ByteArrayOutputStream(); + DataOutputStream rvaDos = new DataOutputStream(rvaBytes); + DataOutputStream riaDos = new DataOutputStream(riaBytes); + + rvaDos.writeShort(countVisible); + riaDos.writeShort(countInvisible); + + // put the annotations in the right output stream + for (int i = 0; i < vec.size(); i++) { + AnnotationGen a = vec.get(i); + if (a.isRuntimeVisible()) + a.dump(rvaDos); + else + a.dump(riaDos); + } + + rvaDos.close(); + riaDos.close(); + + byte[] rvaData = rvaBytes.toByteArray(); + byte[] riaData = riaBytes.toByteArray(); + + int rvaIndex = -1; + int riaIndex = -1; + + if (rvaData.length > 2) + rvaIndex = cp.addUtf8("RuntimeVisibleAnnotations"); + if (riaData.length > 2) + riaIndex = cp.addUtf8("RuntimeInvisibleAnnotations"); + + List newAttributes = new ArrayList(); + if (rvaData.length > 2) { + newAttributes.add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, rvaData, cp)); + } + if (riaData.length > 2) { + newAttributes.add(new RuntimeInvisibleAnnotations(riaIndex, riaData.length, riaData, cp)); + } + + return newAttributes; + } catch (IOException e) { + System.err.println("IOException whilst processing annotations"); + e.printStackTrace(); + } + return null; + } + + /** + * Annotations against a class are stored in one of four attribute kinds: - RuntimeVisibleParameterAnnotations - + * RuntimeInvisibleParameterAnnotations + */ + // OPTIMIZE looks heavyweight? + public static Attribute[] getParameterAnnotationAttributes(ConstantPool cp, List[] /* + * Array of lists, array size depends on + * #params + */vec) { + + int visCount[] = new int[vec.length]; + int totalVisCount = 0; + int invisCount[] = new int[vec.length]; + int totalInvisCount = 0; + try { + + for (int i = 0; i < vec.length; i++) { + List l = vec[i]; + if (l != null) { + for (Iterator iter = l.iterator(); iter.hasNext();) { + AnnotationGen element = (AnnotationGen) iter.next(); + if (element.isRuntimeVisible()) { + visCount[i]++; + totalVisCount++; + } else { + invisCount[i]++; + totalInvisCount++; + } + } + } + } + + // Lets do the visible ones + ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream(); + DataOutputStream rvaDos = new DataOutputStream(rvaBytes); + rvaDos.writeByte(vec.length); // First goes number of parameters + + for (int i = 0; i < vec.length; i++) { + rvaDos.writeShort(visCount[i]); + if (visCount[i] > 0) { + List l = vec[i]; + for (Iterator iter = l.iterator(); iter.hasNext();) { + AnnotationGen element = (AnnotationGen) iter.next(); + if (element.isRuntimeVisible()) + element.dump(rvaDos); + } + } + } + rvaDos.close(); + + // Lets do the invisible ones + ByteArrayOutputStream riaBytes = new ByteArrayOutputStream(); + DataOutputStream riaDos = new DataOutputStream(riaBytes); + riaDos.writeByte(vec.length); // First goes number of parameters + + for (int i = 0; i < vec.length; i++) { + riaDos.writeShort(invisCount[i]); + if (invisCount[i] > 0) { + List l = vec[i]; + for (Iterator iter = l.iterator(); iter.hasNext();) { + AnnotationGen element = (AnnotationGen) iter.next(); + if (!element.isRuntimeVisible()) + element.dump(riaDos); + } + } + } + riaDos.close(); + + byte[] rvaData = rvaBytes.toByteArray(); + byte[] riaData = riaBytes.toByteArray(); + + int rvaIndex = -1; + int riaIndex = -1; + + if (totalVisCount > 0) + rvaIndex = cp.addUtf8("RuntimeVisibleParameterAnnotations"); + if (totalInvisCount > 0) + riaIndex = cp.addUtf8("RuntimeInvisibleParameterAnnotations"); + + List newAttributes = new ArrayList(); + + if (totalVisCount > 0) { + newAttributes.add(new RuntimeVisibleParameterAnnotations(rvaIndex, rvaData.length, rvaData, cp)); + } + + if (totalInvisCount > 0) { + newAttributes.add(new RuntimeInvisibleParameterAnnotations(riaIndex, riaData.length, riaData, cp)); + } + + return newAttributes.toArray(new Attribute[] {}); + } catch (IOException e) { + System.err.println("IOException whilst processing parameter annotations"); + e.printStackTrace(); + } + return null; + } + + public static class ResultHolder { + private String result; + private int consumed; + + public static final ResultHolder BYTE = new ResultHolder("byte", 1); + public static final ResultHolder CHAR = new ResultHolder("char", 1); + public static final ResultHolder DOUBLE = new ResultHolder("double", 1); + public static final ResultHolder FLOAT = new ResultHolder("float", 1); + public static final ResultHolder INT = new ResultHolder("int", 1); + public static final ResultHolder LONG = new ResultHolder("long", 1); + public static final ResultHolder SHORT = new ResultHolder("short", 1); + public static final ResultHolder BOOLEAN = new ResultHolder("boolean", 1); + public static final ResultHolder VOID = new ResultHolder("void", 1); + + public ResultHolder(String s, int c) { + result = s; + consumed = c; + } + + public String getResult() { + return result; + } + + public int getConsumedChars() { + return consumed; + } + } + + /** + * Return type of signature as a byte value as defined in Constants + * + * @param signature in format described above + * @return type of signature + * @see Constants + */ + public static final byte typeOfSignature(String signature) throws ClassFormatException { + try { + switch (signature.charAt(0)) { + case 'B': + return Constants.T_BYTE; + case 'C': + return Constants.T_CHAR; + case 'D': + return Constants.T_DOUBLE; + case 'F': + return Constants.T_FLOAT; + case 'I': + return Constants.T_INT; + case 'J': + return Constants.T_LONG; + case 'L': + return Constants.T_REFERENCE; + case '[': + return Constants.T_ARRAY; + case 'V': + return Constants.T_VOID; + case 'Z': + return Constants.T_BOOLEAN; + case 'S': + return Constants.T_SHORT; + default: + throw new ClassFormatException("Invalid method signature: " + signature); + } + } catch (StringIndexOutOfBoundsException e) { + throw new ClassFormatException("Invalid method signature: " + signature); + } + } + + public static final byte typeOfSignature(char c) throws ClassFormatException { + switch (c) { + case 'B': + return Constants.T_BYTE; + case 'C': + return Constants.T_CHAR; + case 'D': + return Constants.T_DOUBLE; + case 'F': + return Constants.T_FLOAT; + case 'I': + return Constants.T_INT; + case 'J': + return Constants.T_LONG; + case 'L': + return Constants.T_REFERENCE; + case '[': + return Constants.T_ARRAY; + case 'V': + return Constants.T_VOID; + case 'Z': + return Constants.T_BOOLEAN; + case 'S': + return Constants.T_SHORT; + default: + throw new ClassFormatException("Invalid type of signature: " + c); + } + } + + /** + * Disassemble a stream of byte codes and return the string representation. + * + * @param bytes stream of bytes + * @param constant_pool Array of constants + * @param verbose be verbose, e.g. print constant pool index + * @return String representation of byte code + */ + public static final String codeToString(ByteSequence bytes, ConstantPool constant_pool, boolean verbose) throws IOException { + short opcode = (short) bytes.readUnsignedByte(); + int default_offset = 0, low, high, npairs; + int index, vindex, constant; + int[] match, jump_table; + int no_pad_bytes = 0, offset; + StringBuffer buf = new StringBuffer(Constants.OPCODE_NAMES[opcode]); + + /* + * Special case: Skip (0-3) padding bytes, i.e., the following bytes are 4-byte-aligned + */ + if ((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) { + int remainder = bytes.getIndex() % 4; + no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; + + for (int i = 0; i < no_pad_bytes; i++) { + byte b = bytes.readByte(); + if (b != 0) + System.err.println("Warning: Padding byte != 0 in " + Constants.OPCODE_NAMES[opcode] + ":" + b); + } + + // Both cases have a field default_offset in common + default_offset = bytes.readInt(); + } + + switch (opcode) { + /* + * Table switch has variable length arguments. + */ + case Constants.TABLESWITCH: + low = bytes.readInt(); + high = bytes.readInt(); + + offset = bytes.getIndex() - 12 - no_pad_bytes - 1; + default_offset += offset; + + buf.append("\tdefault = " + default_offset + ", low = " + low + ", high = " + high + "("); + + jump_table = new int[high - low + 1]; + for (int i = 0; i < jump_table.length; i++) { + jump_table[i] = offset + bytes.readInt(); + buf.append(jump_table[i]); + if (i < jump_table.length - 1) + buf.append(", "); + } + buf.append(")"); + break; + + /* + * Lookup switch has variable length arguments. + */ + case Constants.LOOKUPSWITCH: { + + npairs = bytes.readInt(); + offset = bytes.getIndex() - 8 - no_pad_bytes - 1; + + match = new int[npairs]; + jump_table = new int[npairs]; + default_offset += offset; + + buf.append("\tdefault = " + default_offset + ", npairs = " + npairs + " ("); + + for (int i = 0; i < npairs; i++) { + match[i] = bytes.readInt(); + jump_table[i] = offset + bytes.readInt(); + buf.append("(" + match[i] + ", " + jump_table[i] + ")"); + if (i < npairs - 1) + buf.append(", "); + } + buf.append(")"); + } + break; + + // Two address bytes + offset from start of byte stream form the jump target + case Constants.GOTO: + case Constants.IFEQ: + case Constants.IFGE: + case Constants.IFGT: + case Constants.IFLE: + case Constants.IFLT: + case Constants.JSR: + case Constants.IFNE: + case Constants.IFNONNULL: + case Constants.IFNULL: + case Constants.IF_ACMPEQ: + case Constants.IF_ACMPNE: + case Constants.IF_ICMPEQ: + case Constants.IF_ICMPGE: + case Constants.IF_ICMPGT: + case Constants.IF_ICMPLE: + case Constants.IF_ICMPLT: + case Constants.IF_ICMPNE: + buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readShort())); + break; + + // 32-bit wide jumps + case Constants.GOTO_W: + case Constants.JSR_W: + buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readInt())); + break; + + // Index byte references local variable (register) + case Constants.ALOAD: + case Constants.ASTORE: + case Constants.DLOAD: + case Constants.DSTORE: + case Constants.FLOAD: + case Constants.FSTORE: + case Constants.ILOAD: + case Constants.ISTORE: + case Constants.LLOAD: + case Constants.LSTORE: + case Constants.RET: + if (wide) { + vindex = bytes.readUnsignedShort(); + wide = false; // Clear flag + } else + vindex = bytes.readUnsignedByte(); + buf.append("\t\t%" + vindex); + break; + + /* + * Remember wide byte which is used to form a 16-bit address in the following instruction. Relies on that the method is + * called again with the following opcode. + */ + case Constants.WIDE: + wide = true; + buf.append("\t(wide)"); + break; + + // Array of basic type + case Constants.NEWARRAY: + buf.append("\t\t<" + Constants.TYPE_NAMES[bytes.readByte()] + ">"); + break; + + // Access object/class fields + case Constants.GETFIELD: + case Constants.GETSTATIC: + case Constants.PUTFIELD: + case Constants.PUTSTATIC: + index = bytes.readUnsignedShort(); + buf.append("\t\t" + constant_pool.constantToString(index, Constants.CONSTANT_Fieldref) + + (verbose ? " (" + index + ")" : "")); + break; + + // Operands are references to classes in constant pool + case Constants.NEW: + case Constants.CHECKCAST: + buf.append("\t"); + case Constants.INSTANCEOF: + index = bytes.readUnsignedShort(); + buf.append("\t<" + constant_pool.constantToString(index, Constants.CONSTANT_Class) + ">" + + (verbose ? " (" + index + ")" : "")); + break; + + // Operands are references to methods in constant pool + case Constants.INVOKESPECIAL: + case Constants.INVOKESTATIC: + case Constants.INVOKEVIRTUAL: + index = bytes.readUnsignedShort(); + buf.append("\t" + constant_pool.constantToString(index, Constants.CONSTANT_Methodref) + + (verbose ? " (" + index + ")" : "")); + break; + + case Constants.INVOKEINTERFACE: + index = bytes.readUnsignedShort(); + int nargs = bytes.readUnsignedByte(); // historical, redundant + buf.append("\t" + constant_pool.constantToString(index, Constants.CONSTANT_InterfaceMethodref) + + (verbose ? " (" + index + ")\t" : "") + nargs + "\t" + bytes.readUnsignedByte()); // Last byte is a reserved + // space + break; + + // Operands are references to items in constant pool + case Constants.LDC_W: + case Constants.LDC2_W: + index = bytes.readUnsignedShort(); + buf.append("\t\t" + constant_pool.constantToString(index, constant_pool.getConstant(index).getTag()) + + (verbose ? " (" + index + ")" : "")); + break; + + case Constants.LDC: + index = bytes.readUnsignedByte(); + buf.append("\t\t" + constant_pool.constantToString(index, constant_pool.getConstant(index).getTag()) + + (verbose ? " (" + index + ")" : "")); + break; + + // Array of references + case Constants.ANEWARRAY: + index = bytes.readUnsignedShort(); + buf.append("\t\t<" + compactClassName(constant_pool.getConstantString(index, Constants.CONSTANT_Class), false) + ">" + + (verbose ? " (" + index + ")" : "")); + break; + + // Multidimensional array of references + case Constants.MULTIANEWARRAY: { + index = bytes.readUnsignedShort(); + int dimensions = bytes.readUnsignedByte(); + + buf.append("\t<" + compactClassName(constant_pool.getConstantString(index, Constants.CONSTANT_Class), false) + ">\t" + + dimensions + (verbose ? " (" + index + ")" : "")); + } + break; + + // Increment local variable + case Constants.IINC: + if (wide) { + vindex = bytes.readUnsignedShort(); + constant = bytes.readShort(); + wide = false; + } else { + vindex = bytes.readUnsignedByte(); + constant = bytes.readByte(); + } + buf.append("\t\t%" + vindex + "\t" + constant); + break; + + default: + if ((Constants.iLen[opcode] - 1) > 0) { + for (int i = 0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) { + buf.append("\t\t"); + switch (Constants.TYPE_OF_OPERANDS[opcode][i]) { + case Constants.T_BYTE: + buf.append(bytes.readByte()); + break; + case Constants.T_SHORT: + buf.append(bytes.readShort()); + break; + case Constants.T_INT: + buf.append(bytes.readInt()); + break; + + default: // Never reached + System.err.println("Unreachable default case reached!"); + System.exit(-1); + } + } + } + } + return buf.toString(); + } + + // private helpers + private static final int pow2(int n) { + return 1 << n; } - return null; - } - - public static class ResultHolder { - private String result; - private int consumed; - - public static final ResultHolder BYTE = new ResultHolder("byte",1); - public static final ResultHolder CHAR = new ResultHolder("char",1); - public static final ResultHolder DOUBLE = new ResultHolder("double",1); - public static final ResultHolder FLOAT = new ResultHolder("float",1); - public static final ResultHolder INT = new ResultHolder("int",1); - public static final ResultHolder LONG = new ResultHolder("long",1); - public static final ResultHolder SHORT = new ResultHolder("short",1); - public static final ResultHolder BOOLEAN = new ResultHolder("boolean",1); - public static final ResultHolder VOID = new ResultHolder("void",1); - - public ResultHolder(String s,int c) { - result = s; - consumed = c; - } - - public String getResult() { return result;} - public int getConsumedChars() { return consumed; } - } - - - /** - * Return type of signature as a byte value as defined in Constants - * - * @param signature in format described above - * @return type of signature - * @see Constants - */ - public static final byte typeOfSignature(String signature) throws ClassFormatException { - try { - switch(signature.charAt(0)) { - case 'B' : return Constants.T_BYTE; - case 'C' : return Constants.T_CHAR; - case 'D' : return Constants.T_DOUBLE; - case 'F' : return Constants.T_FLOAT; - case 'I' : return Constants.T_INT; - case 'J' : return Constants.T_LONG; - case 'L' : return Constants.T_REFERENCE; - case '[' : return Constants.T_ARRAY; - case 'V' : return Constants.T_VOID; - case 'Z' : return Constants.T_BOOLEAN; - case 'S' : return Constants.T_SHORT; - default: - throw new ClassFormatException("Invalid method signature: " + signature); - } - } catch(StringIndexOutOfBoundsException e) { - throw new ClassFormatException("Invalid method signature: " + signature); - } - } - - public static final byte typeOfSignature(char c) throws ClassFormatException { - switch(c) { - case 'B' : return Constants.T_BYTE; - case 'C' : return Constants.T_CHAR; - case 'D' : return Constants.T_DOUBLE; - case 'F' : return Constants.T_FLOAT; - case 'I' : return Constants.T_INT; - case 'J' : return Constants.T_LONG; - case 'L' : return Constants.T_REFERENCE; - case '[' : return Constants.T_ARRAY; - case 'V' : return Constants.T_VOID; - case 'Z' : return Constants.T_BOOLEAN; - case 'S' : return Constants.T_SHORT; - default: - throw new ClassFormatException("Invalid type of signature: " + c); - } - } - - /** - * Disassemble a stream of byte codes and return the string representation. - * - * @param bytes stream of bytes - * @param constant_pool Array of constants - * @param verbose be verbose, e.g. print constant pool index - * @return String representation of byte code - */ - public static final String codeToString(ByteSequence bytes, - ConstantPool constant_pool, boolean verbose) throws IOException { - short opcode = (short)bytes.readUnsignedByte(); - int default_offset=0, low, high, npairs; - int index, vindex, constant; - int[] match, jump_table; - int no_pad_bytes=0, offset; - StringBuffer buf = new StringBuffer(Constants.OPCODE_NAMES[opcode]); - - /* Special case: Skip (0-3) padding bytes, i.e., the - * following bytes are 4-byte-aligned - */ - if ((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) { - int remainder = bytes.getIndex() % 4; - no_pad_bytes = (remainder == 0)? 0 : 4 - remainder; - - for (int i=0; i < no_pad_bytes; i++) { - byte b = bytes.readByte(); - if (b != 0) - System.err.println("Warning: Padding byte != 0 in " + Constants.OPCODE_NAMES[opcode] + ":" + b); - } - - // Both cases have a field default_offset in common - default_offset = bytes.readInt(); - } - - switch(opcode) { - /* Table switch has variable length arguments. - */ - case Constants.TABLESWITCH: - low = bytes.readInt(); - high = bytes.readInt(); - - offset = bytes.getIndex() - 12 - no_pad_bytes - 1; - default_offset += offset; - - buf.append("\tdefault = " + default_offset + ", low = " + low + - ", high = " + high + "("); - - jump_table = new int[high - low + 1]; - for (int i=0; i < jump_table.length; i++) { - jump_table[i] = offset + bytes.readInt(); - buf.append(jump_table[i]); - if (i < jump_table.length - 1) buf.append(", "); - } - buf.append(")"); - break; - - /* Lookup switch has variable length arguments. - */ - case Constants.LOOKUPSWITCH: { - - npairs = bytes.readInt(); - offset = bytes.getIndex() - 8 - no_pad_bytes - 1; - - match = new int[npairs]; - jump_table = new int[npairs]; - default_offset += offset; - - buf.append("\tdefault = " + default_offset + ", npairs = " + npairs + " ("); - - for (int i=0; i < npairs; i++) { - match[i] = bytes.readInt(); - jump_table[i] = offset + bytes.readInt(); - buf.append("(" + match[i] + ", " + jump_table[i] + ")"); - if(i < npairs - 1) buf.append(", "); - } - buf.append(")"); - } - break; - - // Two address bytes + offset from start of byte stream form the jump target - case Constants.GOTO: case Constants.IFEQ: case Constants.IFGE: case Constants.IFGT: - case Constants.IFLE: case Constants.IFLT: case Constants.JSR: case Constants.IFNE: - case Constants.IFNONNULL: case Constants.IFNULL: case Constants.IF_ACMPEQ: - case Constants.IF_ACMPNE: case Constants.IF_ICMPEQ: case Constants.IF_ICMPGE: case Constants.IF_ICMPGT: - case Constants.IF_ICMPLE: case Constants.IF_ICMPLT: case Constants.IF_ICMPNE: - buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readShort())); - break; - - // 32-bit wide jumps - case Constants.GOTO_W: case Constants.JSR_W: - buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readInt())); - break; - - // Index byte references local variable (register) - case Constants.ALOAD: case Constants.ASTORE: case Constants.DLOAD: case Constants.DSTORE: case Constants.FLOAD: - case Constants.FSTORE: case Constants.ILOAD: case Constants.ISTORE: case Constants.LLOAD: case Constants.LSTORE: - case Constants.RET: - if (wide) { - vindex = bytes.readUnsignedShort(); - wide=false; // Clear flag - } else - vindex = bytes.readUnsignedByte(); - buf.append("\t\t%" + vindex); - break; - - /* - * Remember wide byte which is used to form a 16-bit address in the - * following instruction. Relies on that the method is called again with - * the following opcode. - */ - case Constants.WIDE: wide=true; buf.append("\t(wide)"); break; - - // Array of basic type - case Constants.NEWARRAY: buf.append("\t\t<" + Constants.TYPE_NAMES[bytes.readByte()] + ">"); break; - - // Access object/class fields - case Constants.GETFIELD: case Constants.GETSTATIC: case Constants.PUTFIELD: case Constants.PUTSTATIC: - index = bytes.readUnsignedShort(); - buf.append("\t\t" + - constant_pool.constantToString(index, Constants.CONSTANT_Fieldref) + - (verbose? " (" + index + ")" : "")); - break; - - // Operands are references to classes in constant pool - case Constants.NEW: - case Constants.CHECKCAST: - buf.append("\t"); - case Constants.INSTANCEOF: - index = bytes.readUnsignedShort(); - buf.append("\t<" + constant_pool.constantToString(index,Constants.CONSTANT_Class) + - ">" + (verbose? " (" + index + ")" : "")); - break; - - // Operands are references to methods in constant pool - case Constants.INVOKESPECIAL: case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL: - index = bytes.readUnsignedShort(); - buf.append("\t" + constant_pool.constantToString(index,Constants.CONSTANT_Methodref) + - (verbose? " (" + index + ")" : "")); - break; - - case Constants.INVOKEINTERFACE: - index = bytes.readUnsignedShort(); - int nargs = bytes.readUnsignedByte(); // historical, redundant - buf.append("\t" + - constant_pool.constantToString(index,Constants.CONSTANT_InterfaceMethodref) + - (verbose? " (" + index + ")\t" : "") + nargs + "\t" + - bytes.readUnsignedByte()); // Last byte is a reserved space - break; - - // Operands are references to items in constant pool - case Constants.LDC_W: case Constants.LDC2_W: - index = bytes.readUnsignedShort(); - buf.append("\t\t" + constant_pool.constantToString - (index, constant_pool.getConstant(index).getTag()) + - (verbose? " (" + index + ")" : "")); - break; - - case Constants.LDC: - index = bytes.readUnsignedByte(); - buf.append("\t\t" + - constant_pool.constantToString - (index, constant_pool.getConstant(index).getTag()) + - (verbose? " (" + index + ")" : "")); - break; - - // Array of references - case Constants.ANEWARRAY: - index = bytes.readUnsignedShort(); - buf.append("\t\t<" + compactClassName(constant_pool.getConstantString - (index, Constants.CONSTANT_Class), false) + - ">" + (verbose? " (" + index + ")": "")); - break; - - // Multidimensional array of references - case Constants.MULTIANEWARRAY: { - index = bytes.readUnsignedShort(); - int dimensions = bytes.readUnsignedByte(); - - buf.append("\t<" + compactClassName(constant_pool.getConstantString - (index, Constants.CONSTANT_Class), false) + - ">\t" + dimensions + (verbose? " (" + index + ")" : "")); - } - break; - - // Increment local variable - case Constants.IINC: - if (wide) { - vindex = bytes.readUnsignedShort(); - constant = bytes.readShort(); - wide = false; - } else { - vindex = bytes.readUnsignedByte(); - constant = bytes.readByte(); - } - buf.append("\t\t%" + vindex + "\t" + constant); - break; - - default: - if ((Constants.iLen[opcode]-1) > 0) { - for (int i=0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) { - buf.append("\t\t"); - switch(Constants.TYPE_OF_OPERANDS[opcode][i]) { - case Constants.T_BYTE: buf.append(bytes.readByte()); break; - case Constants.T_SHORT: buf.append(bytes.readShort()); break; - case Constants.T_INT: buf.append(bytes.readInt()); break; - - default: // Never reached - System.err.println("Unreachable default case reached!"); - System.exit(-1); - } - } - } - } - return buf.toString(); - } - - // private helpers - private static final int pow2(int n) { - return 1 << n; - } } diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/ClassGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/ClassGen.java index 03ed2d910..1fcd4d53e 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/generic/ClassGen.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/ClassGen.java @@ -60,641 +60,696 @@ import java.lang.reflect.Modifier; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.FieldOrMethod; -import org.aspectj.apache.bcel.classfile.Modifiers; import org.aspectj.apache.bcel.classfile.Attribute; import org.aspectj.apache.bcel.classfile.ConstantPool; import org.aspectj.apache.bcel.classfile.Field; +import org.aspectj.apache.bcel.classfile.FieldOrMethod; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.Modifiers; import org.aspectj.apache.bcel.classfile.SourceFile; import org.aspectj.apache.bcel.classfile.Utility; import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; import org.aspectj.apache.bcel.classfile.annotation.RuntimeInvisibleAnnotations; import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations; -/** - * Template class for building up a java class. May be initialized with an - * existing java class (file). - * +/** + * Template class for building up a java class. May be initialized with an existing java class (file). + * * @see JavaClass - * @version $Id: ClassGen.java,v 1.11 2009/09/09 19:56:20 aclement Exp $ - * @author M. Dahm - * - * Upgraded, Andy Clement 9th Mar 06 - calculates SUID + * @version $Id: ClassGen.java,v 1.12 2009/09/09 22:18:20 aclement Exp $ + * @author M. Dahm + * + * Upgraded, Andy Clement 9th Mar 06 - calculates SUID */ public class ClassGen extends Modifiers implements Cloneable { - private String class_name, super_class_name, file_name; - private int class_name_index = -1, superclass_name_index = -1; - private int major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1; - - private ConstantPool cp; - - private ArrayList field_vec = new ArrayList(); - private ArrayList method_vec = new ArrayList(); - private ArrayList attributesList = new ArrayList(); - private ArrayList interface_vec = new ArrayList(); - private ArrayList annotation_vec= new ArrayList(); - - /** Convenience constructor to set up some important values initially. - * - * @param class_name fully qualified class name - * @param super_class_name fully qualified superclass name - * @param file_name source file name - * @param access_flags access qualifiers - * @param interfaces implemented interfaces - * @param cp constant pool to use - */ - public ClassGen(String class_name, String super_class_name, String file_name, - int access_flags, String[] interfaces, ConstantPool cp) { - this.class_name = class_name; - this.super_class_name = super_class_name; - this.file_name = file_name; - this.modifiers = access_flags; - this.cp = cp; - - // Put everything needed by default into the constant pool and the vectors - if (file_name != null) { - addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, cp.addUtf8(file_name), cp)); - } - - class_name_index = cp.addClass(class_name); - superclass_name_index = cp.addClass(super_class_name); - - if (interfaces != null) { - for(int i=0; i < interfaces.length; i++) - addInterface(interfaces[i]); - } - } - - /** Convenience constructor to set up some important values initially. - * - * @param class_name fully qualified class name - * @param super_class_name fully qualified superclass name - * @param file_name source file name - * @param access_flags access qualifiers - * @param interfaces implemented interfaces - */ - public ClassGen(String class_name, String super_class_name, String file_name, - int access_flags, String[] interfaces) { - this(class_name, super_class_name, file_name, access_flags, interfaces, - new ConstantPool()); - } - - /** - * Initialize with existing class. - * @param clazz JavaClass object (e.g. read from file) - */ - public ClassGen(JavaClass clazz) { - class_name_index = clazz.getClassNameIndex(); - superclass_name_index = clazz.getSuperclassNameIndex(); - class_name = clazz.getClassName(); - super_class_name = clazz.getSuperclassName(); - file_name = clazz.getSourceFileName(); - modifiers = clazz.getModifiers(); - cp = clazz.getConstantPool().copy(); - major = clazz.getMajor(); - minor = clazz.getMinor(); - - Attribute[] attributes = clazz.getAttributes(); - // J5TODO: Could make unpacking lazy, done on first reference - AnnotationGen[] annotations = unpackAnnotations(attributes); - Method[] methods = clazz.getMethods(); - Field[] fields = clazz.getFields(); - String[] interfaces = clazz.getInterfaceNames(); - - for(int i=0; i < interfaces.length; i++) - addInterface(interfaces[i]); - - //Attribute[] attrs = attributes.getAttributes(); - for(int i=0; i < attributes.length; i++) { - // Dont add attributes for annotations as those will have been unpacked - if (annotations.length==0) { - addAttribute(attributes[i]); - } else if (!attributes[i].getName().equals("RuntimeVisibleAnnotations") && - !attributes[i].getName().equals("RuntimeInvisibleAnnotations")) { - addAttribute(attributes[i]); - } - } - for(int i=0; i < annotations.length; i++) - addAnnotation(annotations[i]); - - for(int i=0; i < methods.length; i++) { - Method m = methods[i]; - addMethod(m); - } - - for(int i=0; i < fields.length; i++) - addField(fields[i]); - } - - /** - * Look for attributes representing annotations and unpack them. - */ - private AnnotationGen[] unpackAnnotations(Attribute[] attrs) { - List /*AnnotationGen*/ annotationGenObjs = new ArrayList(); - for (int i = 0; i < attrs.length; i++) { - Attribute attr = attrs[i]; - if (attr instanceof RuntimeVisibleAnnotations) { - RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations)attr; - List annos = rva.getAnnotations(); - for (Iterator iter = annos.iterator(); iter.hasNext();) { - AnnotationGen a = iter.next(); - annotationGenObjs.add(new AnnotationGen(a,getConstantPool(),false)); + private String class_name, super_class_name, file_name; + private int class_name_index = -1, superclass_name_index = -1; + private int major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1; + + private ConstantPool cp; + + private List field_vec = new ArrayList(); + private List method_vec = new ArrayList(); + private List attributesList = new ArrayList(); + private List interface_vec = new ArrayList(); + private List annotationsList = new ArrayList(); + + /** + * Convenience constructor to set up some important values initially. + * + * @param class_name fully qualified class name + * @param super_class_name fully qualified superclass name + * @param file_name source file name + * @param access_flags access qualifiers + * @param interfaces implemented interfaces + * @param cp constant pool to use + */ + public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces, + ConstantPool cp) { + this.class_name = class_name; + this.super_class_name = super_class_name; + this.file_name = file_name; + this.modifiers = access_flags; + this.cp = cp; + + // Put everything needed by default into the constant pool and the vectors + if (file_name != null) { + addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, cp.addUtf8(file_name), cp)); + } + + class_name_index = cp.addClass(class_name); + superclass_name_index = cp.addClass(super_class_name); + + if (interfaces != null) { + for (int i = 0; i < interfaces.length; i++) + addInterface(interfaces[i]); + } + } + + /** + * Convenience constructor to set up some important values initially. + * + * @param class_name fully qualified class name + * @param super_class_name fully qualified superclass name + * @param file_name source file name + * @param access_flags access qualifiers + * @param interfaces implemented interfaces + */ + public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces) { + this(class_name, super_class_name, file_name, access_flags, interfaces, new ConstantPool()); + } + + /** + * Initialize with existing class. + * + * @param clazz JavaClass object (e.g. read from file) + */ + public ClassGen(JavaClass clazz) { + class_name_index = clazz.getClassNameIndex(); + superclass_name_index = clazz.getSuperclassNameIndex(); + class_name = clazz.getClassName(); + super_class_name = clazz.getSuperclassName(); + file_name = clazz.getSourceFileName(); + modifiers = clazz.getModifiers(); + cp = clazz.getConstantPool().copy(); + major = clazz.getMajor(); + minor = clazz.getMinor(); + + Attribute[] attributes = clazz.getAttributes(); + // J5TODO: Could make unpacking lazy, done on first reference + AnnotationGen[] annotations = unpackAnnotations(attributes); + Method[] methods = clazz.getMethods(); + Field[] fields = clazz.getFields(); + String[] interfaces = clazz.getInterfaceNames(); + + for (int i = 0; i < interfaces.length; i++) + addInterface(interfaces[i]); + + // Attribute[] attrs = attributes.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + // Dont add attributes for annotations as those will have been unpacked + if (annotations.length == 0) { + addAttribute(attributes[i]); + } else if (!attributes[i].getName().equals("RuntimeVisibleAnnotations") + && !attributes[i].getName().equals("RuntimeInvisibleAnnotations")) { + addAttribute(attributes[i]); } - } else if (attr instanceof RuntimeInvisibleAnnotations) { - RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations)attr; - List annos = ria.getAnnotations(); - for (Iterator iter = annos.iterator(); iter.hasNext();) { - AnnotationGen a = iter.next(); - annotationGenObjs.add(new AnnotationGen(a,getConstantPool(),false)); + } + for (int i = 0; i < annotations.length; i++) + addAnnotation(annotations[i]); + + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + addMethod(m); + } + + for (int i = 0; i < fields.length; i++) + addField(fields[i]); + } + + /** + * Look for attributes representing annotations and unpack them. + */ + private AnnotationGen[] unpackAnnotations(Attribute[] attrs) { + List /* AnnotationGen */ annotationGenObjs = new ArrayList(); + for (int i = 0; i < attrs.length; i++) { + Attribute attr = attrs[i]; + if (attr instanceof RuntimeVisibleAnnotations) { + RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; + List annos = rva.getAnnotations(); + for (Iterator iter = annos.iterator(); iter.hasNext();) { + AnnotationGen a = iter.next(); + annotationGenObjs.add(new AnnotationGen(a, getConstantPool(), false)); + } + } else if (attr instanceof RuntimeInvisibleAnnotations) { + RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; + List annos = ria.getAnnotations(); + for (Iterator iter = annos.iterator(); iter.hasNext();) { + AnnotationGen a = iter.next(); + annotationGenObjs.add(new AnnotationGen(a, getConstantPool(), false)); + } } } + return annotationGenObjs.toArray(new AnnotationGen[] {}); } - return annotationGenObjs.toArray(new AnnotationGen[]{}); - } - - /** - * @return the (finally) built up Java class object. - */ - public JavaClass getJavaClass() { - int[] interfaces = getInterfaces(); - Field[] fields = getFields(); - Method[] methods = getMethods(); - - // OPTIMIZE sort out this mangling of arrays and collections - Attribute[] attributes = null; - if (annotation_vec.size()==0) { - attributes = getAttributes(); - } else { - // TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations' - Attribute[] annAttributes = Utility.getAnnotationAttributes(cp,annotation_vec); - attributes = new Attribute[attributesList.size()+annAttributes.length]; - attributesList.toArray(attributes); - System.arraycopy(annAttributes,0,attributes,attributesList.size(),annAttributes.length); - } - - // Must be last since the above calls may still add something to it - ConstantPool cp = this.cp.getFinalConstantPool(); - - return new JavaClass(class_name_index, superclass_name_index, - file_name, major, minor, modifiers, - cp, interfaces, fields, methods, attributes); - } - - /** - * Add an interface to this class, i.e., this class has to implement it. - * @param name interface to implement (fully qualified class name) - */ - public void addInterface(String name) { - interface_vec.add(name); - } - - /** - * Remove an interface from this class. - * @param name interface to remove (fully qualified name) - */ - public void removeInterface(String name) { - interface_vec.remove(name); - } - - /** - * @return major version number of class file - */ - public int getMajor() { return major; } - - /** Set major version number of class file, default value is 45 (JDK 1.1) - * @param major major version number - */ - public void setMajor(int major) { - this.major = major; - } - - /** Set minor version number of class file, default value is 3 (JDK 1.1) - * @param minor minor version number - */ - public void setMinor(int minor) { - this.minor = minor; - } - - /** - * @return minor version number of class file - */ - public int getMinor() { return minor; } - - /** - * Add an attribute to this class. - * @param a attribute to add - */ - public void addAttribute(Attribute a) { attributesList.add(a); } - - public void addAnnotation(AnnotationGen a) { annotation_vec.add(a); } - /** - * Add a method to this class. - * @param m method to add - */ - public void addMethod(Method m) { method_vec.add(m); } - - /** - * Convenience method. - * - * Add an empty constructor to this class that does nothing but calling super(). - * @param access rights for constructor - */ - public void addEmptyConstructor(int access_flags) { - InstructionList il = new InstructionList(); - il.append(InstructionConstants.THIS); // Push `this' - il.append(new InvokeInstruction(Constants.INVOKESPECIAL,cp.addMethodref(super_class_name,"", "()V"))); - il.append(InstructionConstants.RETURN); - - MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, - "", class_name, il, cp); - mg.setMaxStack(1); - mg.setMaxLocals(); - addMethod(mg.getMethod()); - } - - /** - * Add a field to this class. - * @param f field to add - */ - public void addField(Field f) { field_vec.add(f); } - - public boolean containsField(Field f) { return field_vec.contains(f); } - - /** @return field object with given name, or null - */ - public Field containsField(String name) { - for(Iterator e=field_vec.iterator(); e.hasNext(); ) { - Field f = e.next(); - if(f.getName().equals(name)) - return f; - } - - return null; - } - - /** @return method object with given name and signature, or null - */ - public Method containsMethod(String name, String signature) { - for(Iterator e=method_vec.iterator(); e.hasNext();) { - Method m = e.next(); - if(m.getName().equals(name) && m.getSignature().equals(signature)) - return m; - } - - return null; - } - - /** - * Remove an attribute from this class. - * @param a attribute to remove - */ - public void removeAttribute(Attribute a) { attributesList.remove(a); } - public void removeAnnotation(AnnotationGen a) {annotation_vec.remove(a);} - - /** - * Remove a method from this class. - * @param m method to remove - */ - public void removeMethod(Method m) { method_vec.remove(m); } - - /** Replace given method with new one. If the old one does not exist - * add the new_ method to the class anyway. - */ - public void replaceMethod(Method old, Method new_) { - if(new_ == null) - throw new ClassGenException("Replacement method must not be null"); - - int i = method_vec.indexOf(old); - - if (i < 0) - method_vec.add(new_); - else - method_vec.set(i, new_); - } - - /** Replace given field with new one. If the old one does not exist - * add the new_ field to the class anyway. - */ - public void replaceField(Field old, Field new_) { - if(new_ == null) - throw new ClassGenException("Replacement method must not be null"); - - int i = field_vec.indexOf(old); - - if(i < 0) - field_vec.add(new_); - else - field_vec.set(i, new_); - } - - /** - * Remove a field to this class. - * @param f field to remove - */ - public void removeField(Field f) { field_vec.remove(f); } - - public String getClassName() { return class_name; } - public String getSuperclassName() { return super_class_name; } - public String getFileName() { return file_name; } - - public void setClassName(String name) { - class_name = name.replace('/', '.'); - class_name_index = cp.addClass(name); - } - - public void setSuperclassName(String name) { - super_class_name = name.replace('/', '.'); - superclass_name_index = cp.addClass(name); - } - - public Method[] getMethods() { - Method[] methods = new Method[method_vec.size()]; - method_vec.toArray(methods); - return methods; - } - - public void setMethods(Method[] methods) { - method_vec.clear(); - for(int m=0; m0) classmods|=Constants.ACC_ABSTRACT; - } else { - classmods|=Constants.ACC_ABSTRACT; - } - } - - dos.writeInt(classmods); - - // 3. ordered list of interfaces - List list = new ArrayList(); - String[] names = getInterfaceNames(); - if (names!=null) { - Arrays.sort(names); - for (int i = 0; i < names.length; i++) dos.writeUTF(names[i]); - } - - // 4. ordered list of fields (ignoring private static and private transient fields): - // (relevant modifiers are ACC_PUBLIC, ACC_PRIVATE, - // ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, - // ACC_TRANSIENT) - list.clear(); - for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; - if (!(field.isPrivate() && field.isStatic()) && - !(field.isPrivate() && field.isTransient())) list.add(field); + + /** + * @return the (finally) built up Java class object. + */ + public JavaClass getJavaClass() { + int[] interfaces = getInterfaces(); + Field[] fields = getFields(); + Method[] methods = getMethods(); + + Collection attributes = null; + if (annotationsList.size() == 0) { + attributes = attributesList; + } else { + // TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations' + attributes = new ArrayList(); + attributes.addAll(Utility.getAnnotationAttributes(cp, annotationsList)); + attributes.addAll(attributesList); } - Collections.sort(list,new FieldComparator()); - int relevantFlags = Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED | - Constants.ACC_STATIC | Constants.ACC_FINAL | Constants.ACC_VOLATILE | Constants.ACC_TRANSIENT; - for (Iterator iter = list.iterator(); iter.hasNext();) { - Field f = (Field) iter.next(); - dos.writeUTF(f.getName()); - dos.writeInt(relevantFlags&f.getModifiers()); - dos.writeUTF(f.getType().getSignature()); + + // Must be last since the above calls may still add something to it + ConstantPool cp = this.cp.getFinalConstantPool(); + + return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, modifiers, cp, interfaces, fields, + methods, attributes.toArray(new Attribute[attributes.size()]));// OPTIMIZE avoid toArray()? + } + + /** + * Add an interface to this class, i.e., this class has to implement it. + * + * @param name interface to implement (fully qualified class name) + */ + public void addInterface(String name) { + interface_vec.add(name); + } + + /** + * Remove an interface from this class. + * + * @param name interface to remove (fully qualified name) + */ + public void removeInterface(String name) { + interface_vec.remove(name); + } + + /** + * @return major version number of class file + */ + public int getMajor() { + return major; + } + + /** + * Set major version number of class file, default value is 45 (JDK 1.1) + * + * @param major major version number + */ + public void setMajor(int major) { + this.major = major; + } + + /** + * Set minor version number of class file, default value is 3 (JDK 1.1) + * + * @param minor minor version number + */ + public void setMinor(int minor) { + this.minor = minor; + } + + /** + * @return minor version number of class file + */ + public int getMinor() { + return minor; + } + + /** + * Add an attribute to this class. + * + * @param a attribute to add + */ + public void addAttribute(Attribute a) { + attributesList.add(a); + } + + public void addAnnotation(AnnotationGen a) { + annotationsList.add(a); + } + + /** + * Add a method to this class. + * + * @param m method to add + */ + public void addMethod(Method m) { + method_vec.add(m); + } + + /** + * Convenience method. + * + * Add an empty constructor to this class that does nothing but calling super(). + * + * @param access rights for constructor + */ + public void addEmptyConstructor(int access_flags) { + InstructionList il = new InstructionList(); + il.append(InstructionConstants.THIS); // Push `this' + il.append(new InvokeInstruction(Constants.INVOKESPECIAL, cp.addMethodref(super_class_name, "", "()V"))); + il.append(InstructionConstants.RETURN); + + MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "", class_name, il, cp); + mg.setMaxStack(1); + mg.setMaxLocals(); + addMethod(mg.getMethod()); + } + + /** + * Add a field to this class. + * + * @param f field to add + */ + public void addField(Field f) { + field_vec.add(f); + } + + public boolean containsField(Field f) { + return field_vec.contains(f); + } + + /** + * @return field object with given name, or null + */ + public Field containsField(String name) { + for (Iterator e = field_vec.iterator(); e.hasNext();) { + Field f = e.next(); + if (f.getName().equals(name)) + return f; } - // some up front method processing: discover clinit, init and ordinary methods of interest: - list.clear(); // now used for methods - List ctors = new ArrayList(); - boolean hasClinit = false; - for (int i = 0; i < methods.length; i++) { - Method m = methods[i]; - boolean couldBeInitializer = m.getName().charAt(0)=='<'; - if (couldBeInitializer && m.getName().equals("")) { - hasClinit=true; - } else if (couldBeInitializer && m.getName().equals("")) { - if (!m.isPrivate()) ctors.add(m); - } else { - if (!m.isPrivate()) list.add(m); - } + return null; + } + + /** + * @return method object with given name and signature, or null + */ + public Method containsMethod(String name, String signature) { + for (Iterator e = method_vec.iterator(); e.hasNext();) { + Method m = e.next(); + if (m.getName().equals(name) && m.getSignature().equals(signature)) + return m; } - Collections.sort(ctors, new ConstructorComparator()); - Collections.sort(list, new MethodComparator()); - - - // 5. If a class initializer exists, write out the following: - // 1. The name of the method, . - // 2. The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer. - // 3. The descriptor of the method, ()V. - if (hasClinit) { - dos.writeUTF(""); - dos.writeInt(Modifier.STATIC); - dos.writeUTF("()V"); - } - - // for methods and constructors: - // ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, - // ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT - relevantFlags = - Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED | - Constants.ACC_STATIC | Constants.ACC_FINAL | Constants.ACC_SYNCHRONIZED | - Constants.ACC_NATIVE | Constants.ACC_ABSTRACT | Constants.ACC_STRICT; - - // 6. sorted non-private constructors - for (Iterator iter = ctors.iterator(); iter.hasNext();) { - Method m = iter.next(); - dos.writeUTF(m.getName()); // - dos.writeInt(relevantFlags & m.getModifiers()); - dos.writeUTF(m.getSignature().replace('/','.')); + + return null; + } + + /** + * Remove an attribute from this class. + * + * @param a attribute to remove + */ + public void removeAttribute(Attribute a) { + attributesList.remove(a); + } + + public void removeAnnotation(AnnotationGen a) { + annotationsList.remove(a); + } + + /** + * Remove a method from this class. + * + * @param m method to remove + */ + public void removeMethod(Method m) { + method_vec.remove(m); + } + + /** + * Replace given method with new one. If the old one does not exist add the new_ method to the class anyway. + */ + public void replaceMethod(Method old, Method new_) { + if (new_ == null) + throw new ClassGenException("Replacement method must not be null"); + + int i = method_vec.indexOf(old); + + if (i < 0) + method_vec.add(new_); + else + method_vec.set(i, new_); + } + + /** + * Replace given field with new one. If the old one does not exist add the new_ field to the class anyway. + */ + public void replaceField(Field old, Field new_) { + if (new_ == null) + throw new ClassGenException("Replacement method must not be null"); + + int i = field_vec.indexOf(old); + + if (i < 0) + field_vec.add(new_); + else + field_vec.set(i, new_); + } + + /** + * Remove a field to this class. + * + * @param f field to remove + */ + public void removeField(Field f) { + field_vec.remove(f); + } + + public String getClassName() { + return class_name; + } + + public String getSuperclassName() { + return super_class_name; + } + + public String getFileName() { + return file_name; + } + + public void setClassName(String name) { + class_name = name.replace('/', '.'); + class_name_index = cp.addClass(name); + } + + public void setSuperclassName(String name) { + super_class_name = name.replace('/', '.'); + superclass_name_index = cp.addClass(name); + } + + public Method[] getMethods() { + Method[] methods = new Method[method_vec.size()]; + method_vec.toArray(methods); + return methods; + } + + public void setMethods(Method[] methods) { + method_vec.clear(); + for (int m = 0; m < methods.length; m++) + addMethod(methods[m]); + } + + public void setFields(Field[] fs) { + field_vec.clear(); + for (int m = 0; m < fs.length; m++) + addField(fs[m]); + } + + public void setMethodAt(Method method, int pos) { + method_vec.set(pos, method); + } + + public Method getMethodAt(int pos) { + return method_vec.get(pos); + } + + public String[] getInterfaceNames() { + int size = interface_vec.size(); + String[] interfaces = new String[size]; + + interface_vec.toArray(interfaces); + return interfaces; + } + + public int[] getInterfaces() { + int size = interface_vec.size(); + int[] interfaces = new int[size]; + + for (int i = 0; i < size; i++) + interfaces[i] = cp.addClass(interface_vec.get(i)); + + return interfaces; + } + + public Field[] getFields() { + Field[] fields = new Field[field_vec.size()]; + field_vec.toArray(fields); + return fields; + } + + public Collection getAttributes() { + return attributesList; + } + + // J5TODO: Should we make calling unpackAnnotations() lazy and put it in here? + public AnnotationGen[] getAnnotations() { + AnnotationGen[] annotations = new AnnotationGen[annotationsList.size()]; + annotationsList.toArray(annotations); + return annotations; + } + + public ConstantPool getConstantPool() { + return cp; + } + + public void setConstantPool(ConstantPool constant_pool) { + cp = constant_pool; + } + + public void setClassNameIndex(int class_name_index) { + this.class_name_index = class_name_index; + class_name = cp.getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.'); + } + + public void setSuperclassNameIndex(int superclass_name_index) { + this.superclass_name_index = superclass_name_index; + super_class_name = cp.getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.'); + } + + public int getSuperclassNameIndex() { + return superclass_name_index; + } + + public int getClassNameIndex() { + return class_name_index; + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + System.err.println(e); + return null; } + } + + // J5SUPPORT: + + /** + * Returns true if this class represents an annotation type + */ + public final boolean isAnnotation() { + return (modifiers & Constants.ACC_ANNOTATION) != 0; + } + + /** + * Returns true if this class represents an enum type + */ + public final boolean isEnum() { + return (modifiers & Constants.ACC_ENUM) != 0; + } + + /** + * Calculate the SerialVersionUID for a class. + */ + public long getSUID() { + try { + Field[] fields = getFields(); + Method[] methods = getMethods(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + // 1. classname + dos.writeUTF(getClassName()); + + // 2. classmodifiers: ACC_PUBLIC, ACC_FINAL, ACC_INTERFACE, and ACC_ABSTRACT + int classmods = 0; + classmods |= (isPublic() ? Constants.ACC_PUBLIC : 0); + classmods |= (isFinal() ? Constants.ACC_FINAL : 0); + classmods |= (isInterface() ? Constants.ACC_INTERFACE : 0); + + if (isAbstract()) { + // if an interface then abstract is only set if it has methods + if (isInterface()) { + if (methods.length > 0) + classmods |= Constants.ACC_ABSTRACT; + } else { + classmods |= Constants.ACC_ABSTRACT; + } + } + + dos.writeInt(classmods); + + // 3. ordered list of interfaces + List list = new ArrayList(); + String[] names = getInterfaceNames(); + if (names != null) { + Arrays.sort(names); + for (int i = 0; i < names.length; i++) + dos.writeUTF(names[i]); + } + + // 4. ordered list of fields (ignoring private static and private transient fields): + // (relevant modifiers are ACC_PUBLIC, ACC_PRIVATE, + // ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, + // ACC_TRANSIENT) + list.clear(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (!(field.isPrivate() && field.isStatic()) && !(field.isPrivate() && field.isTransient())) + list.add(field); + } + Collections.sort(list, new FieldComparator()); + int relevantFlags = Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED | Constants.ACC_STATIC + | Constants.ACC_FINAL | Constants.ACC_VOLATILE | Constants.ACC_TRANSIENT; + for (Iterator iter = list.iterator(); iter.hasNext();) { + Field f = (Field) iter.next(); + dos.writeUTF(f.getName()); + dos.writeInt(relevantFlags & f.getModifiers()); + dos.writeUTF(f.getType().getSignature()); + } + + // some up front method processing: discover clinit, init and ordinary methods of interest: + list.clear(); // now used for methods + List ctors = new ArrayList(); + boolean hasClinit = false; + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + boolean couldBeInitializer = m.getName().charAt(0) == '<'; + if (couldBeInitializer && m.getName().equals("")) { + hasClinit = true; + } else if (couldBeInitializer && m.getName().equals("")) { + if (!m.isPrivate()) + ctors.add(m); + } else { + if (!m.isPrivate()) + list.add(m); + } + } + Collections.sort(ctors, new ConstructorComparator()); + Collections.sort(list, new MethodComparator()); + + // 5. If a class initializer exists, write out the following: + // 1. The name of the method, . + // 2. The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer. + // 3. The descriptor of the method, ()V. + if (hasClinit) { + dos.writeUTF(""); + dos.writeInt(Modifier.STATIC); + dos.writeUTF("()V"); + } - // 7. sorted non-private methods - for (Iterator iter = list.iterator(); iter.hasNext();) { - Method m = (Method) iter.next(); - dos.writeUTF(m.getName()); - dos.writeInt(relevantFlags & m.getModifiers()); - dos.writeUTF(m.getSignature().replace('/','.')); + // for methods and constructors: + // ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, + // ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT + relevantFlags = Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED | Constants.ACC_STATIC + | Constants.ACC_FINAL | Constants.ACC_SYNCHRONIZED | Constants.ACC_NATIVE | Constants.ACC_ABSTRACT + | Constants.ACC_STRICT; + + // 6. sorted non-private constructors + for (Iterator iter = ctors.iterator(); iter.hasNext();) { + Method m = iter.next(); + dos.writeUTF(m.getName()); // + dos.writeInt(relevantFlags & m.getModifiers()); + dos.writeUTF(m.getSignature().replace('/', '.')); + } + + // 7. sorted non-private methods + for (Iterator iter = list.iterator(); iter.hasNext();) { + Method m = (Method) iter.next(); + dos.writeUTF(m.getName()); + dos.writeInt(relevantFlags & m.getModifiers()); + dos.writeUTF(m.getSignature().replace('/', '.')); + } + dos.flush(); + dos.close(); + byte[] bs = baos.toByteArray(); + MessageDigest md = MessageDigest.getInstance("SHA"); + byte[] result = md.digest(bs); + + long suid = 0L; + int pos = result.length > 8 ? 7 : result.length - 1; // use the bytes we have + while (pos >= 0) { + suid = suid << 8 | ((long) result[pos--] & 0xff); + } + + // if it was definetly 8 everytime... + // long suid = ((long)(sha[0]&0xff) | (long)(sha[1]&0xff) << 8 | + // (long)(sha[2]&0xff) << 16 | (long)(sha[3]&0xff) << 24 | + // (long)(sha[4]&0xff) << 32 | (long)(sha[5]&0xff) << 40 | + // (long)(sha[6]&0xff) << 48 | (long)(sha[7]&0xff) << 56); + return suid; + } catch (Exception e) { + System.err.println("Unable to calculate suid for " + getClassName()); + e.printStackTrace(); + throw new RuntimeException("Unable to calculate suid for " + getClassName() + ": " + e.toString()); } - dos.flush(); - dos.close(); - byte[] bs = baos.toByteArray(); - MessageDigest md = MessageDigest.getInstance("SHA"); - byte[] result = md.digest(bs); - - long suid = 0L; - int pos = result.length>8?7:result.length-1; // use the bytes we have - while (pos>=0) { - suid = suid<<8 | ((long)result[pos--]&0xff); - } - - // if it was definetly 8 everytime... - // long suid = ((long)(sha[0]&0xff) | (long)(sha[1]&0xff) << 8 | - // (long)(sha[2]&0xff) << 16 | (long)(sha[3]&0xff) << 24 | - // (long)(sha[4]&0xff) << 32 | (long)(sha[5]&0xff) << 40 | - // (long)(sha[6]&0xff) << 48 | (long)(sha[7]&0xff) << 56); - return suid; - } catch (Exception e) { - System.err.println("Unable to calculate suid for "+getClassName()); - e.printStackTrace(); - throw new RuntimeException("Unable to calculate suid for "+getClassName()+": "+e.toString()); - } - } - - private static class FieldComparator implements Comparator { - public int compare(Object arg0, Object arg1) { - return ((Field)arg0).getName().compareTo(((Field)arg1).getName()); + } + + private static class FieldComparator implements Comparator { + public int compare(Object arg0, Object arg1) { + return ((Field) arg0).getName().compareTo(((Field) arg1).getName()); } - } - private static class ConstructorComparator implements Comparator { - public int compare(Object arg0, Object arg1) { + } + + private static class ConstructorComparator implements Comparator { + public int compare(Object arg0, Object arg1) { // can ignore the name... - return ((Method)arg0).getSignature().compareTo(((Method)arg1).getSignature()); + return ((Method) arg0).getSignature().compareTo(((Method) arg1).getSignature()); } - } - private static class MethodComparator implements Comparator { - public int compare(Object arg0, Object arg1) { - Method m1 = (Method)arg0; - Method m2 = (Method)arg1; + } + + private static class MethodComparator implements Comparator { + public int compare(Object arg0, Object arg1) { + Method m1 = (Method) arg0; + Method m2 = (Method) arg1; int result = m1.getName().compareTo(m2.getName()); - if (result!=0) return result; + if (result != 0) + return result; return m1.getSignature().compareTo(m2.getSignature()); } - } - - public boolean hasAttribute(String attributeName) { - for (Iterator iter = attributesList.iterator(); iter.hasNext();) { - Attribute attr = iter.next(); - if (attr.getName().equals(attributeName)) return true; - } - return false; - } - - public Attribute getAttribute(String attributeName) { - for (Iterator iter = attributesList.iterator(); iter.hasNext();) { + } + + public boolean hasAttribute(String attributeName) { + for (Attribute attr : attributesList) { + if (attr.getName().equals(attributeName)) { + return true; + } + } + return false; + } + + public Attribute getAttribute(String attributeName) { + for (Iterator iter = attributesList.iterator(); iter.hasNext();) { Attribute attr = iter.next(); - if (attr.getName().equals(attributeName)) return attr; - } + if (attr.getName().equals(attributeName)) + return attr; + } return null; - } + } } diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/FieldGenOrMethodGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/FieldGenOrMethodGen.java index 94437abd5..372c7b7b9 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/generic/FieldGenOrMethodGen.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/FieldGenOrMethodGen.java @@ -55,27 +55,28 @@ package org.aspectj.apache.bcel.generic; */ import java.util.ArrayList; +import java.util.Collection; import java.util.List; -import org.aspectj.apache.bcel.classfile.Modifiers; import org.aspectj.apache.bcel.classfile.Attribute; import org.aspectj.apache.bcel.classfile.ConstantPool; +import org.aspectj.apache.bcel.classfile.Modifiers; import org.aspectj.apache.bcel.classfile.Utility; import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; +import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations; /** - * Super class for FieldGen and MethodGen objects, since they have some methods - * in common! + * Super class for FieldGen and MethodGen objects, since they have some methods in common! * - * @version $Id: FieldGenOrMethodGen.java,v 1.5 2009/09/09 19:56:20 aclement Exp $ + * @version $Id: FieldGenOrMethodGen.java,v 1.6 2009/09/09 22:18:20 aclement Exp $ * @author M. Dahm */ public abstract class FieldGenOrMethodGen extends Modifiers implements Cloneable { - + protected String name; protected Type type; protected ConstantPool cp; - private ArrayList/**/ attributeList = new ArrayList(); + private ArrayList/* */ attributeList = new ArrayList(); private ArrayList annotationList = new ArrayList(); protected FieldGenOrMethodGen() { @@ -129,10 +130,10 @@ public abstract class FieldGenOrMethodGen extends Modifiers implements Cloneable annotationList.clear(); } - public List/**/ getAttributes() { + public List/* */ getAttributes() { return attributeList; } - + public Attribute[] getAttributesImmutable() { Attribute[] attributes = new Attribute[attributeList.size()]; attributeList.toArray(attributes); @@ -140,12 +141,12 @@ public abstract class FieldGenOrMethodGen extends Modifiers implements Cloneable } protected void addAnnotationsAsAttribute(ConstantPool cp) { - Attribute[] attrs = Utility.getAnnotationAttributes(cp,annotationList); - if (attrs!=null) { - for (int i = 0; i < attrs.length; i++) { - addAttribute(attrs[i]); - } - } + Collection attrs = Utility.getAnnotationAttributes(cp, annotationList); + if (attrs != null) { + for (Attribute attr : attrs) { + addAttribute(attr); + } + } } public AnnotationGen[] getAnnotations() { @@ -157,6 +158,7 @@ public abstract class FieldGenOrMethodGen extends Modifiers implements Cloneable public abstract String getSignature(); // OPTIMIZE clone any use??? + @Override public Object clone() { try { return super.clone(); diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/ReferenceType.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/ReferenceType.java index 37e28b3f3..ae3be0c00 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/generic/ReferenceType.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/ReferenceType.java @@ -61,7 +61,7 @@ import org.aspectj.apache.bcel.classfile.JavaClass; /** * Super class for object and array types. * - * @version $Id: ReferenceType.java,v 1.5 2008/08/28 15:36:59 aclement Exp $ + * @version $Id: ReferenceType.java,v 1.6 2009/09/09 22:18:20 aclement Exp $ * @author M. Dahm */ public abstract class ReferenceType extends Type { @@ -265,8 +265,8 @@ public abstract class ReferenceType extends Type { // this and t are ObjectTypes, see above. ObjectType thiz = (ObjectType) this; ObjectType other = (ObjectType) t; - JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); - JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); + JavaClass[] thiz_sups = Repository.lookupClass(thiz.getClassName()).getSuperClasses();// getSuperClasses(thiz.getClassName()); + JavaClass[] other_sups = Repository.lookupClass(other.getClassName()).getSuperClasses();// getSuperClasses(other.getClassName()); if (thiz_sups == null || other_sups == null) { return null; diff --git a/bcel-builder/src/org/aspectj/apache/bcel/util/ClassQueue.java b/bcel-builder/src/org/aspectj/apache/bcel/util/ClassQueue.java deleted file mode 100644 index d424a2625..000000000 --- a/bcel-builder/src/org/aspectj/apache/bcel/util/ClassQueue.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.aspectj.apache.bcel.util; - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" and - * "Apache BCEL" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * "Apache BCEL", nor may "Apache" appear in their name, without - * prior written permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - */ -import java.util.LinkedList; -import org.aspectj.apache.bcel.classfile.JavaClass; - -/** - * Utility class implementing a (typesafe) queue of JavaClass - * objects. - * - * @version $Id: ClassQueue.java,v 1.4 2009/09/09 19:56:20 aclement Exp $ - * @author M. Dahm - * @see ClassVector -*/ -public class ClassQueue implements java.io.Serializable { - protected LinkedList vec = new LinkedList(); - - public void enqueue(JavaClass clazz) { vec.addLast(clazz); } - - public JavaClass dequeue() { - return vec.removeFirst(); - } - - public boolean empty() { return vec.isEmpty(); } - - public String toString() { - return vec.toString(); - } -} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/util/ClassVector.java b/bcel-builder/src/org/aspectj/apache/bcel/util/ClassVector.java deleted file mode 100644 index bb12c40be..000000000 --- a/bcel-builder/src/org/aspectj/apache/bcel/util/ClassVector.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.aspectj.apache.bcel.util; - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" and - * "Apache BCEL" must not be used to endorse or promote products - * derived from this software without prior written permission. For - * written permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * "Apache BCEL", nor may "Apache" appear in their name, without - * prior written permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - */ -import java.util.ArrayList; -import org.aspectj.apache.bcel.classfile.JavaClass; - -/** - * Utility class implementing a (typesafe) collection of JavaClass - * objects. Contains the most important methods of a Vector. - * - * @version $Id: ClassVector.java,v 1.4 2009/09/09 19:56:20 aclement Exp $ - * @author M. Dahm - * @see ClassQueue -*/ -public class ClassVector implements java.io.Serializable { - protected ArrayList vec = new ArrayList(); - - public void addElement(JavaClass clazz) { vec.add(clazz); } - public JavaClass elementAt(int index) { return vec.get(index); } - public void removeElementAt(int index) { vec.remove(index); } - - public JavaClass[] toArray() { - JavaClass[] classes = new JavaClass[vec.size()]; - vec.toArray(classes); - return classes; - } -} -- 2.39.5