Index: src/org/aspectj/asm/AsmManager.java =================================================================== RCS file: /cvsroot/tools/org.aspectj/modules/asm/src/org/aspectj/asm/AsmManager.java,v --- src/org/aspectj/asm/AsmManager.java 7 Apr 2009 01:31:04 -0000 1.46 +++ src/org/aspectj/asm/AsmManager.java 13 Aug 2009 15:42:13 -0000 @@ -83,9 +83,11 @@ // below to the AjState for a compilation and recover it if switching // between projects. protected IHierarchy hierarchy; - - /* Map from String > String - it maps absolute paths for - * inpath dirs/jars to workspace relative paths suitable for handle inclusion */ + + /* + * Map from String > String - it maps absolute paths for inpath dirs/jars to workspace relative paths suitable for handle + * inclusion + */ protected Map inpathMap; private IRelationshipMap mapper; private IElementHandleProvider handleProvider; @@ -654,16 +656,16 @@ } - private String getTypeNameFromHandle(String handle,Map cache) { - String typename = (String)cache.get(handle); - if (typename!=null) { + private String getTypeNameFromHandle(String handle, Map cache) { + String typename = (String) cache.get(handle); + if (typename != null) { return typename; } // inpath handle - but for which type? // let's do it the slow way, we can optimize this with a cache perhaps int hasPackage = handle.indexOf('<'); - int typeLocation = handle.indexOf('['); - if (typeLocation==-1) { + int typeLocation = handle.indexOf('['); + if (typeLocation == -1) { typeLocation = handle.indexOf('}'); } if (typeLocation == -1) { @@ -671,15 +673,16 @@ return ""; } StringBuffer qualifiedTypeNameFromHandle = new StringBuffer(); - if (hasPackage!=-1) { - qualifiedTypeNameFromHandle.append(handle.substring(hasPackage+1,handle.indexOf('(',hasPackage))); + if (hasPackage != -1) { + qualifiedTypeNameFromHandle.append(handle.substring(hasPackage + 1, handle.indexOf('(', hasPackage))); qualifiedTypeNameFromHandle.append('.'); } - qualifiedTypeNameFromHandle.append(handle.substring(typeLocation+1)); + qualifiedTypeNameFromHandle.append(handle.substring(typeLocation + 1)); typename = qualifiedTypeNameFromHandle.toString(); - cache.put(handle,typename); + cache.put(handle, typename); return typename; } + /** * two kinds of relationships * @@ -726,7 +729,7 @@ if (isPhantomHandle(hid)) { // inpath handle - but for which type? // TODO promote cache for reuse during one whole model update - if (!getTypeNameFromHandle(hid,handleToTypenameCache).equals(typename)) { + if (!getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) { continue; } } @@ -805,7 +808,7 @@ // they need removing for (Iterator targetsIter = targets.iterator(); targetsIter.hasNext();) { String targethid = (String) targetsIter.next(); - if (isPhantomHandle(hid) && !getTypeNameFromHandle(hid,handleToTypenameCache).equals(typename)) { + if (isPhantomHandle(hid) && !getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) { continue; } // Does this point to the same type? @@ -910,13 +913,13 @@ } return (type.equals(containingType)); } - + /** * @param handle a JDT like handle, following the form described in AsmRelationshipProvider.findOrFakeUpNode * @return true if the handle contains ';' - the char indicating that it is a phantom handle */ private boolean isPhantomHandle(String handle) { - return handle.indexOf(HandleProviderDelimiter.PHANTOM.getDelimiter())!=-1; + return handle.indexOf(HandleProviderDelimiter.PHANTOM.getDelimiter()) != -1; } /** @@ -1307,7 +1310,208 @@ } public String getHandleElementForInpath(String binaryPath) { - return (String)inpathMap.get(new File(binaryPath)); + return (String) inpathMap.get(new File(binaryPath)); + } + + private List pieces = new ArrayList(); + + private Object intern(String substring) { + int lastIdx = -1; + if ((lastIdx = substring.lastIndexOf('/')) != -1) { + String pkg = substring.substring(0, lastIdx); + String type = substring.substring(lastIdx + 1); + pkg = internOneThing(pkg); + type = internOneThing(type); + return new String[] { pkg, type }; + } else { + return internOneThing(substring); + } } + private String internOneThing(String substring) { + // simple name + for (int p = 0, max = pieces.size(); p < max; p++) { + String s = (String) pieces.get(p); + if (s.equals(substring)) { + return s; + } + } + pieces.add(substring); + return substring; + } + + /** + * What we can rely on:
+ * - it is a method signature of the form (La/B;Lc/D;)LFoo;
+ * - there are no generics
+ * + * What we must allow for: - may use primitive refs (single chars rather than L) + */ +/* + public List compress(String s) { + int openParen = 0; + int closeParen = s.indexOf(')'); + int pos = 1; + List compressed = new ArrayList(); + // do the parens + while (pos < closeParen) { + char ch = s.charAt(pos); + if (ch == 'L') { + int idx = s.indexOf(';', pos); + compressed.add(intern(s.substring(pos + 1, idx))); + pos = idx + 1; + } else if (ch == '[') { + int x = pos; + while (s.charAt(++pos) == '[') + ; + // now pos will point at something not an array + compressed.add(intern(s.substring(x, pos))); // intern the [[[[[[ + char ch2 = s.charAt(pos); + if (ch2 == 'L') { + int idx = s.indexOf(';', pos); + compressed.add(intern(s.substring(pos + 1, idx))); + pos = idx + 1; + } else if (ch2 == 'T') { + int idx = s.indexOf(';'); + compressed.add(intern(s.substring(pos, idx + 1))); // should be TT; + pos = idx + 1; + } else { + compressed.add(toCharacter(s.charAt(pos))); + pos++; + } + } else { + // it is a primitive ref (SVBCZJ) + compressed.add(toCharacter(ch)); + pos++; + } + } + // do the return type + pos++; + char ch = s.charAt(pos); + if (ch == 'L') { + int idx = s.indexOf(';', pos); + compressed.add(intern(s.substring(pos, idx))); + } else if (ch == '[') { + int x = pos; + while (s.charAt(++pos) == '[') + ; + // now pos will point at something not an array + compressed.add(intern(s.substring(x, pos))); // intern the [[[[[[ + char ch2 = s.charAt(pos); + if (ch2 == 'L') { + int idx = s.indexOf(';', pos); + compressed.add(intern(s.substring(pos + 1, idx))); + pos = idx + 1; + } else if (ch2 == 'T') { + int idx = s.indexOf(';'); + compressed.add(intern(s.substring(pos, idx + 1))); // should be TT; + pos = idx + 2; + } else { + compressed.add(toCharacter(s.charAt(pos))); + pos++; + } + } else { + // it is a primitive ref (SVBCZJ) + compressed.add(new Character(ch)); + } + return compressed; + + // char delimiter = '/'; + // int pos = -1; + // List compressed = new ArrayList(); + // int start = 0; + // while ((pos = s.indexOf(delimiter, start)) != -1) { + // String part = s.substring(start, pos); + // int alreadyRecorded = pieces.indexOf(part); + // if (alreadyRecorded != -1) { + // compressed.add(new Integer(alreadyRecorded)); + // } else { + // compressed.add(new Integer(pieces.size())); + // pieces.add(part); + // } + // start = pos + 1; + // } + // // last piece + // String part = s.substring(start, s.length()); + // int alreadyRecorded = pieces.indexOf(part); + // if (alreadyRecorded != -1) { + // compressed.add(youkirtyounew Integer(alreadyRecorded)); + // } else { + // compressed.add(new Integer(pieces.size())); + // pieces.add(part); + // } + // return compressed; + } + + static final Character charB = new Character('B'); + static final Character charS = new Character('S'); + static final Character charI = new Character('I'); + static final Character charF = new Character('F'); + static final Character charD = new Character('D'); + static final Character charJ = new Character('J'); + static final Character charC = new Character('C'); + static final Character charV = new Character('V'); + static final Character charZ = new Character('Z'); + + private Character toCharacter(char ch) { + switch (ch) { + case 'B': + return charB; + case 'S': + return charS; + case 'I': + return charI; + case 'F': + return charF; + case 'D': + return charD; + case 'J': + return charJ; + case 'C': + return charC; + case 'V': + return charV; + case 'Z': + return charZ; + default: + throw new IllegalStateException(new Character(ch).toString()); + } + } + + public String decompress(List refs, char delimiter) { + StringBuilder result = new StringBuilder(); + result.append("("); + for (int i = 0, max = refs.size() - 1; i < max; i++) { + result.append(unintern(refs.get(i))); + } + result.append(")"); + result.append(unintern(refs.get(refs.size() - 1))); + return result.toString(); + } + + private String unintern(Object o) { + if (o instanceof Character) { + return ((Character) o).toString(); + } else if (o instanceof String[]) { + String[] strings = (String[]) o; + StringBuilder sb = new StringBuilder(); + sb.append('L'); + sb.append(strings[0]).append('/').append(strings[1]); + sb.append(';'); + return sb.toString(); + } else { // String + String so = (String) o; + if (so.endsWith(";")) { + // will be TT; + return so; + } else { + StringBuilder sb = new StringBuilder(); + sb.append('L'); + sb.append(so); + sb.append(';'); + return sb.toString(); + } + } + } + */ } Index: src/org/aspectj/asm/internal/ProgramElement.java =================================================================== RCS file: /cvsroot/tools/org.aspectj/modules/asm/src/org/aspectj/asm/internal/ProgramElement.java,v --- src/org/aspectj/asm/internal/ProgramElement.java 11 Jun 2009 22:53:41 -0000 1.47 +++ src/org/aspectj/asm/internal/ProgramElement.java 13 Aug 2009 15:42:13 -0000 @@ -305,12 +305,6 @@ return s; } - public String getBytecodeSignature() { - String s = (String) kvpairs.get("bytecodeSignature"); - // if (s==null) return UNDEFINED; - return s; - } - public void setBytecodeName(String s) { if (kvpairs == Collections.EMPTY_MAP) kvpairs = new HashMap(); @@ -318,9 +312,36 @@ } public void setBytecodeSignature(String s) { - if (kvpairs == Collections.EMPTY_MAP) - kvpairs = new HashMap(); + initMap(); + // Different kinds of format here. The one worth compressing starts with a '(': + // (La/b/c/D;Le/f/g/G;)Ljava/lang/String; + // maybe want to avoid generics initially. + // boolean worthCompressing = s.charAt(0) == '(' && s.indexOf('<') == -1 && s.indexOf('P') == -1; // starts parentheses and + // no + // // generics + // if (worthCompressing) { + // kvpairs.put("bytecodeSignatureCompressed", asm.compress(s)); + // } else { kvpairs.put("bytecodeSignature", s); + // } + } + + public String getBytecodeSignature() { + String s = (String) kvpairs.get("bytecodeSignature"); + // if (s == null) { + // List compressed = (List) kvpairs.get("bytecodeSignatureCompressed"); + // if (compressed != null) { + // return asm.decompress(compressed, '/'); + // } + // } + // if (s==null) return UNDEFINED; + return s; + } + + private void initMap() { + if (kvpairs == Collections.EMPTY_MAP) { + kvpairs = new HashMap(); + } } public String getSourceSignature() { @@ -549,22 +570,24 @@ } public String getHandleIdentifier(boolean create) { + String h = null; if (null == handle && create) { if (asm == null && name.equals("")) { - handle = ""; + h = ""; } else { try { - handle = asm.getHandleProvider().createHandleIdentifier(this); + h = asm.getHandleProvider().createHandleIdentifier(this); } catch (ArrayIndexOutOfBoundsException aioobe) { throw new RuntimeException("AIOOBE whilst building handle for " + this, aioobe); } } } - return handle; + setHandleIdentifier(h); + return h; } public void setHandleIdentifier(String handle) { - this.handle = handle; + // this.handle = handle; } public List getParameterNames() { Index: src/org/aspectj/asm/internal/JDTLikeHandleProvider.java =================================================================== RCS file: /cvsroot/tools/org.aspectj/modules/asm/src/org/aspectj/asm/internal/JDTLikeHandleProvider.java,v --- src/org/aspectj/asm/internal/JDTLikeHandleProvider.java 27 Jul 2009 17:27:25 -0000 1.25 +++ src/org/aspectj/asm/internal/JDTLikeHandleProvider.java 13 Aug 2009 15:42:13 -0000 @@ -31,10 +31,6 @@ private final AsmManager asm; - // Need to keep our own count of the number of initializers - // because this information cannot be gained from the ipe. - private int initializerCounter = 0; - private static final char[] empty = new char[] {}; private static final char[] countDelim = new char[] { HandleProviderDelimiter.COUNT.getDelimiter() }; @@ -46,7 +42,6 @@ } public String createHandleIdentifier(IProgramElement ipe) { - // AjBuildManager.setupModel --> top of the tree is either // or the .lst file if (ipe == null || (ipe.getKind().equals(IProgramElement.Kind.FILE_JAVA) && ipe.getName().equals(""))) { @@ -284,7 +279,74 @@ return CharOperation.concat(countDelim, new Integer(count).toString().toCharArray()); } } else if (ipe.getKind().equals(IProgramElement.Kind.INITIALIZER)) { - return String.valueOf(++initializerCounter).toCharArray(); + // return String.valueOf(++initializerCounter).toCharArray(); + // Look at any peer advice + int count = 1; + List kids = ipe.getParent().getChildren(); + String ipeSig = ipe.getBytecodeSignature(); + // remove return type from the signature - it should not be included in the comparison + int idx = 0; + if (ipeSig != null && ((idx = ipeSig.indexOf(")")) != -1)) { + ipeSig = ipeSig.substring(0, idx); + } + if (ipeSig != null) { + if (ipeSig.indexOf("Lorg/aspectj/lang") != -1) { + if (ipeSig.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) { + ipeSig = ipeSig.substring(0, ipeSig.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;")); + } + if (ipeSig.endsWith("Lorg/aspectj/lang/JoinPoint;")) { + ipeSig = ipeSig.substring(0, ipeSig.lastIndexOf("Lorg/aspectj/lang/JoinPoint;")); + } + if (ipeSig.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) { + ipeSig = ipeSig.substring(0, ipeSig.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;")); + } + } + } + for (Iterator iterator = kids.iterator(); iterator.hasNext();) { + IProgramElement object = (IProgramElement) iterator.next(); + if (object.equals(ipe)) { + break; + } + if (object.getKind() == ipe.getKind()) { + if (object.getName().equals(ipe.getName())) { + String sig1 = object.getBytecodeSignature(); + if (sig1 != null && (idx = sig1.indexOf(")")) != -1) { + sig1 = sig1.substring(0, idx); + } + // this code needs a speed overhaul... and some proper tests + // Two static parts because one may be enclosing jpsp (269522) + if (sig1 != null) { + if (sig1.indexOf("Lorg/aspectj/lang") != -1) { + if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) { + sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;")); + } + if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint;")) { + sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint;")); + } + if (sig1.endsWith("Lorg/aspectj/lang/JoinPoint$StaticPart;")) { + sig1 = sig1.substring(0, sig1.lastIndexOf("Lorg/aspectj/lang/JoinPoint$StaticPart;")); + } + } + } + + if (sig1 == null && ipeSig == null || (sig1 != null && sig1.equals(ipeSig))) { + String existingHandle = object.getHandleIdentifier(); + int suffixPosition = existingHandle.indexOf('!'); + if (suffixPosition != -1) { + count = new Integer(existingHandle.substring(suffixPosition + 1)).intValue() + 1; + } else { + if (count == 1) { + count = 2; + } + } + } + } + } + } + // if (count > 1) { + return new Integer(count).toString().toCharArray(); + // return CharOperation.concat(countDelim, new Integer(count).toString().toCharArray()); + // } } else if (ipe.getKind().equals(IProgramElement.Kind.CODE)) { int index = CharOperation.lastIndexOf('!', byteCodeName); if (index != -1) { @@ -421,6 +483,6 @@ public void initialize() { // reset the initializer count. This ensures we return the // same handle as JDT for initializers. - initializerCounter = 0; + // initializerCounter = 0; } } Index: src/org/aspectj/asm/internal/CharOperation.java =================================================================== RCS file: /cvsroot/tools/org.aspectj/modules/asm/src/org/aspectj/asm/internal/CharOperation.java,v --- src/org/aspectj/asm/internal/CharOperation.java 4 Sep 2008 19:08:10 -0000 1.3 +++ src/org/aspectj/asm/internal/CharOperation.java 13 Aug 2009 15:42:13 -0000 @@ -16,6 +16,10 @@ */ public class CharOperation { + public static final char[][] NO_CHAR_CHAR = new char[0][]; + + public static final char[] NO_CHAR = new char[0]; + /** * Taken from org.aspectj.org.eclipse.jdt.core.compiler.CharOperation */ @@ -34,6 +38,44 @@ return result; } + public static final char[][] subarray(char[][] array, int start, int end) { + if (end == -1) + end = array.length; + if (start > end) + return null; + if (start < 0) + return null; + if (end > array.length) + return null; + + char[][] result = new char[end - start][]; + System.arraycopy(array, start, result, 0, end - start); + return result; + } + + public static final char[][] splitOn(char divider, char[] array) { + int length = array == null ? 0 : array.length; + if (length == 0) + return NO_CHAR_CHAR; + + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy(array, last, split[currentWord++], 0, i - last); + last = i + 1; + } + } + split[currentWord] = new char[length - last]; + System.arraycopy(array, last, split[currentWord], 0, length - last); + return split; + } + /** * Taken from org.aspectj.org.eclipse.jdt.core.compiler.CharOperation */ @@ -88,6 +130,67 @@ return true; } + final static public String toString(char[][] array) { + char[] result = concatWith(array, '.'); + return new String(result); + } + + public static final char[] concatWith(char[][] array, char separator) { + int length = array == null ? 0 : array.length; + if (length == 0) + return CharOperation.NO_CHAR; + + int size = length - 1; + int index = length; + while (--index >= 0) { + if (array[index].length == 0) + size--; + else + size += array[index].length; + } + if (size <= 0) + return CharOperation.NO_CHAR; + char[] result = new char[size]; + index = length; + while (--index >= 0) { + length = array[index].length; + if (length > 0) { + System.arraycopy(array[index], 0, result, (size -= length), length); + if (--size >= 0) + result[size] = separator; + } + } + return result; + } + + public static final int hashCode(char[] array) { + int length = array.length; + int hash = length == 0 ? 31 : array[0]; + if (length < 8) { + for (int i = length; --i > 0;) + hash = (hash * 31) + array[i]; + } else { + // 8 characters is enough to compute a decent hash code, don't waste time examining every character + for (int i = length - 1, last = i > 16 ? i - 16 : 0; i > last; i -= 2) + hash = (hash * 31) + array[i]; + } + return hash & 0x7FFFFFFF; + } + + public static final boolean equals(char[][] first, char[][] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i])) + return false; + return true; + } + /** * Taken from org.aspectj.org.eclipse.jdt.core.compiler.CharOperation */