Index: main/java/org/apache/harmony/pack200/Segment.java =================================================================== --- main/java/org/apache/harmony/pack200/Segment.java (revision 640642) +++ main/java/org/apache/harmony/pack200/Segment.java (working copy) @@ -216,22 +216,13 @@ // add inner class attribute (if required) boolean addInnerClassesAttr = false; // TODO: remove the debug info below -// String debugClass = getClassBands().getClassThis()[classNum]; -// SegmentUtils.debug("buildClassFile: class is " + debugClass); -// if("com/ibm/collaboration/realtime/application/RTCMainPlugin".equals(foo)) { -// SegmentUtils.debug("self halt"); -// } + String debugClass = getClassBands().getClassThis()[classNum]; + SegmentUtils.debug("buildClassFile: class is " + debugClass); IcTuple[] ic_local = getClassBands().getIcLocal()[classNum]; boolean ic_local_sent = false; if(ic_local != null) { ic_local_sent = true; } - // TODO: remove the debug code below -// if(ic_local_sent) { -// for(int xx = 0; xx < ic_local.length; xx++) { -// SegmentUtils.debug("ic_local[" + xx + "]=" + ic_local[xx]); -// } -// } InnerClassesAttribute innerClassesAttribute = new InnerClassesAttribute("InnerClasses"); IcTuple[] ic_relevant = getIcBands().getRelevantIcTuples(fullName, cp); IcTuple[] ic_stored = computeIcStored(ic_local, ic_relevant); Index: main/java/org/apache/harmony/pack200/IcBands.java =================================================================== --- main/java/org/apache/harmony/pack200/IcBands.java (revision 640642) +++ main/java/org/apache/harmony/pack200/IcBands.java (working copy) @@ -79,14 +79,19 @@ icAll = new IcTuple[icThisClass.length]; int index = 0; for (int i = 0; i < icThisClass.length; i++) { - icAll[i] = new IcTuple(); - icAll[i].C = icThisClass[i]; - icAll[i].F = icFlags[i]; + String icTupleC = null; + int icTupleF = -1; + String icTupleC2 = null; + String icTupleN = null; + + icTupleC = icThisClass[i]; + icTupleF = icFlags[i]; if((icFlags[i] & 1<<16) != 0) { - icAll[i].C2 = icOuterClass[index]; - icAll[i].N = icName[index]; + icTupleC2 = icOuterClass[index]; + icTupleN = icName[index]; index++; } + icAll[i] = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN); } } @@ -106,23 +111,17 @@ IcTuple[] allTuples = getIcTuples(); int allTuplesSize = allTuples.length; for(int index=0; index < allTuplesSize; index++) { - if(allTuples[index].outerClassString().equals(className)) { - // Originally I added all classes (anonymous and not anonymous). - // That yielded bad results on some classes. Adding just - // the non-anonymous classes (which is not what the - // spec specifies) seems to fix up a number of cases - // where the classes are otherwise mismatched. - if(!allTuples[index].isAnonymous()) { - relevantTuples.add(allTuples[index]); - } + if(allTuples[index].shouldAddToRelevantForClassName(className) ) { + relevantTuples.add(allTuples[index]); } } List classPoolClasses = cp.allClasses(); boolean changed = true; - // For every class in both ic_this_class and cp, + // For every class constant in both ic_this_class and cp, // add it to ic_relevant. Repeat until no more // changes to ic_relevant. + while(changed) { changed = false; for(int allTupleIndex=0; allTupleIndex < allTuplesSize; allTupleIndex++) { @@ -141,6 +140,39 @@ } } + // Not part of spec: fix up by adding to relevantTuples the parents + // of inner classes which are themselves inner classes. + // i.e., I think that if Foo$Bar$Baz gets added, Foo$Bar needs to be added + // as well. + + boolean changedFixup = true; + ArrayList tuplesToAdd = new ArrayList(); + while(changedFixup) { + changedFixup = false; + for(int index=0; index < relevantTuples.size(); index++) { + IcTuple aRelevantTuple = (IcTuple)relevantTuples.get(index); + for(int allTupleIndex = 0; allTupleIndex < allTuplesSize; allTupleIndex++) { + if(aRelevantTuple.outerClassString().equals(allTuples[allTupleIndex].thisClassString())) { + if(!aRelevantTuple.outerIsAnonymous()) { + tuplesToAdd.add(allTuples[allTupleIndex]); + } + } + } + } + if(tuplesToAdd.size() > 0) { + Iterator it = tuplesToAdd.iterator(); + while(it.hasNext()) { + IcTuple tuple = (IcTuple)it.next(); + if(!relevantTuples.contains(tuple)) { + changedFixup = true; + relevantTuples.add(tuple); + } + } + tuplesToAdd = new ArrayList(); + } + } + // End not part of the spec. Ugh. + // Now order the result as a subsequence of ic_all IcTuple[] orderedRelevantTuples = new IcTuple[relevantTuples.size()]; int orderedRelevantIndex = 0; Index: main/java/org/apache/harmony/pack200/IcTuple.java =================================================================== --- main/java/org/apache/harmony/pack200/IcTuple.java (revision 640642) +++ main/java/org/apache/harmony/pack200/IcTuple.java (working copy) @@ -20,17 +20,38 @@ public class IcTuple { + public IcTuple(String C, int F, String C2, String N) { + this.C = C; + this.F = F; + this.C2 = C2; + this.N = N; + if(null == N) { + predictSimple = true; + } + if(null == C2) { + predictOuter = true; + } + initializeClassStrings(); + } + + public IcTuple(String C, int F) { + this(C, F, null, null); + } + public static final int NESTED_CLASS_FLAG = 0x00010000; - public String C; // this class - public int F; // flags - public String C2; // outer class - public String N; // name + protected String C; // this class + protected int F; // flags + protected String C2; // outer class + protected String N; // name + private boolean predictSimple = false; + private boolean predictOuter = false; private String cachedOuterClassString = null; private String cachedSimpleClassName = null; private boolean initialized = false; private boolean anonymous = false; private boolean member = true; + private boolean outerIsAnonymous = false; /** * Answer true if the receiver is predicted; @@ -39,7 +60,7 @@ * @return */ public boolean predicted() { - return ((F & NESTED_CLASS_FLAG) == 0); + return predictOuter || predictSimple; } /** @@ -76,9 +97,6 @@ * @return String name of outer class */ public String outerClassString() { - if(!initialized) { - initializeClassStrings(); - } return cachedOuterClassString; } @@ -87,9 +105,6 @@ * @return String name of inner class */ public String simpleClassName() { - if(!initialized) { - initializeClassStrings(); - } return cachedSimpleClassName; } @@ -109,34 +124,73 @@ } public boolean isMember() { - initializeClassStrings(); return member; } public boolean isAnonymous() { - initializeClassStrings(); return anonymous; } + public boolean outerIsAnonymous() { + String [] result = innerBreakAtDollar(cachedOuterClassString); + if(result.length == 0) { + throw new Error("Should have an outer before checking if it's anonymous"); + } + + for(int index=0; index < result.length; index++) { + if(isAllDigits(result[index])) { + return true; + } + } + return false; + } + + public boolean shouldAddToRelevantForClassName(String className) { + // If the outerClassString of the tuple doesn't match the + // class name of the class we're looking through, don't + // consider it relevant. + if(!outerClassString().equals(className)) { + return false; + } + // If it's not anon and the outer is not anon, it's relevant + if(!isAnonymous() && !outerIsAnonymous()) { + return true; + } + + // Otherwise it's not relevant. + return false; + } + private void initializeClassStrings() { if(initialized) { return; } initialized = true; - if(!predicted()) { - cachedOuterClassString = C2; + + if(!predictSimple) { cachedSimpleClassName = N; - return; } + if(!predictOuter) { + cachedOuterClassString = C2; + } // Class names must be calculated from // this class name. String nameComponents[] = innerBreakAtDollar(C); if(nameComponents.length == 0) { - throw new Error("Unable to predict outer class name: " + C); + // Unable to predict outer class + // throw new Error("Unable to predict outer class name: " + C); } if(nameComponents.length == 1) { - throw new Error("Unable to predict inner class name: " + C); + // Unable to predict simple class name + // throw new Error("Unable to predict inner class name: " + C); } + if(nameComponents.length < 2) { + // If we get here, we hope cachedSimpleClassName + // and cachedOuterClassString were caught by the + // predictSimple / predictOuter code above. + return; + } + // If we get to this point, nameComponents.length must be >=2 int lastPosition = nameComponents.length - 1; cachedSimpleClassName = nameComponents[lastPosition]; @@ -153,9 +207,21 @@ cachedOuterClassString += '$'; } } + // TODO: these two blocks are the same as blocks + // above. Can we eliminate some by reworking the logic? + if(!predictSimple) { + cachedSimpleClassName = N; + } + if(!predictOuter) { + cachedOuterClassString = C2; + } if(isAllDigits(cachedSimpleClassName)) { anonymous = true; member = false; + if((F & 65536) == 65536) { + // Predicted class - marking as member + member = true; + } } } @@ -182,14 +248,14 @@ result.append(')'); return result.toString(); } - + public boolean nullSafeEquals(String stringOne, String stringTwo) { if(null==stringOne) { return null==stringTwo; } return stringOne.equals(stringTwo); } - + public boolean equals(Object object) { if(object.getClass() != this.getClass()) { return false; @@ -209,8 +275,32 @@ } return true; } - + public int hashCode() { return 17 + C.hashCode() + C2.hashCode() + N.hashCode(); } + + public String getC() { + return C; + } + + public int getF() { + return F; + } + + public String getC2() { + return C2; + } + + public String getN() { + return N; + } + + public String realOuterClassString() { + int firstDollarPosition = cachedOuterClassString.indexOf('$'); + if(firstDollarPosition <= 0) { + return cachedOuterClassString; + } + return cachedOuterClassString.substring(0, firstDollarPosition); + } } Index: main/java/org/apache/harmony/pack200/ClassBands.java =================================================================== --- main/java/org/apache/harmony/pack200/ClassBands.java (revision 640642) +++ main/java/org/apache/harmony/pack200/ClassBands.java (working copy) @@ -623,25 +623,31 @@ // decided at the end when creating class constant pools icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]]; for (int j = 0; j < icLocal[i].length; j++) { - IcTuple icTuple = new IcTuple(); - icTuple.C = cpClass[classInnerClassesRC[innerClassIndex][j]]; - icTuple.F = classInnerClassesF[innerClassIndex][j]; - if (icTuple.F != 0) { - icTuple.C2 = cpClass[classInnerClassesOuterRCN[innerClassC2NIndex]]; - icTuple.N = cpUTF8[classInnerClassesNameRUN[innerClassC2NIndex]]; + String icTupleC = null; + int icTupleF = -1; + String icTupleC2 = null; + String icTupleN = null; + + icTupleC = cpClass[classInnerClassesRC[innerClassIndex][j]]; + icTupleF = classInnerClassesF[innerClassIndex][j]; + if (icTupleF != 0) { + icTupleC2 = cpClass[classInnerClassesOuterRCN[innerClassC2NIndex]]; + icTupleN = cpUTF8[classInnerClassesNameRUN[innerClassC2NIndex]]; innerClassC2NIndex++; } else { // Get from icBands IcBands icBands = segment.getIcBands(); IcTuple[] icAll = icBands.getIcTuples(); for (int k = 0; k < icAll.length; k++) { - if (icAll[k].C.equals(icTuple.C)) { - icTuple.C2 = icAll[k].C2; - icTuple.N = icAll[k].N; + if (icAll[k].getC().equals(icTupleC)) { + icTupleC2 = icAll[k].getC2(); + icTupleN = icAll[k].getN(); break; } } } + + IcTuple icTuple = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN); icLocal[i][j] = icTuple; } innerClassIndex++; Index: main/java/org/apache/harmony/pack200/bytecode/CPFieldRef.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CPFieldRef.java (revision 640642) +++ main/java/org/apache/harmony/pack200/bytecode/CPFieldRef.java (working copy) @@ -25,6 +25,7 @@ transient int classNameIndex; private CPNameAndType nameAndType; transient int nameAndTypeIndex; + private String cachedComparisonString = null; public CPFieldRef(CPClass className, CPNameAndType descriptor) { super(ConstantPoolEntry.CP_Fieldref); @@ -53,7 +54,10 @@ } public String comparisonString() { - return (className.getName() + Character.MAX_VALUE) + nameAndType.descriptor + Character.MAX_VALUE + nameAndType.name; + if(cachedComparisonString == null) { + cachedComparisonString = (className.getName() + Character.MAX_VALUE) + nameAndType.descriptor + Character.MAX_VALUE + nameAndType.name; + } + return cachedComparisonString; } public int hashCode() { Index: main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (revision 640642) +++ main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (working copy) @@ -57,14 +57,21 @@ // Only add in constant pools, but resolve all types since they may // introduce new constant pool entries // This is a handy way to see what's adding a ClassFileEntry - set a breakpoint on the print -// if(entry instanceof CPFieldRef) { -// SegmentUtils.debug("AAH:" + ((CPFieldRef)entry).comparisonString()); -// if (((CPUTF8)entry).underlyingString().matches("Code")) { -// SegmentUtils.debug("Adding"); +// if(entry instanceof CPLong) { +// org.apache.harmony.pack200.SegmentUtils.debug("AAH:" + ((CPUTF8)entry).underlyingString()); +// if (((CPUTF8)entry).underlyingString().indexOf('\b') != -1) { +// boolean halt = false; +// for(int index=0; index < entries.size(); index++) { +// ClassFileEntry foo = (ClassFileEntry)(entries.get(index)); +// if(foo instanceof CPUTF8) { +// if(((CPUTF8)foo).underlyingString().matches(".*MRUBundleFileList.java.*")) { +// halt = true; +// } +// +// } // } // } if (entry instanceof ConstantPoolEntry) { -// classPoolSet.add(entry); if (!entries.contains(entry)) { entries.add(entry); if (entry instanceof CPLong ||entry instanceof CPDouble) Index: main/java/org/apache/harmony/pack200/bytecode/CPUTF8.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CPUTF8.java (revision 640642) +++ main/java/org/apache/harmony/pack200/bytecode/CPUTF8.java (working copy) @@ -24,6 +24,8 @@ private String utf8; + private String cachedSignatureComparisonString = null; + public CPUTF8(String utf8, int domain) { super(ConstantPoolEntry.CP_UTF8); this.utf8 = utf8; @@ -94,6 +96,9 @@ } public String signatureComparisonString() { + if(cachedSignatureComparisonString != null) { + return cachedSignatureComparisonString; + } // TODO: what to do about inner classes? if(utf8==null) {return "null:utf8 (probably an inner class?)";}; StringBuffer alphaChars = new StringBuffer(); @@ -116,6 +121,9 @@ alphaChars.append(utf8.charAt(index)); } } - return(alphaChars.toString() + extraChars.toString()); + extraChars.append(Character.MAX_VALUE); + extraChars.append(utf8); // make sure the chars are distinct + cachedSignatureComparisonString = alphaChars.toString() + extraChars.toString(); + return(cachedSignatureComparisonString); } } \ No newline at end of file Index: main/java/org/apache/harmony/pack200/bytecode/CPRef.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CPRef.java (revision 640642) +++ main/java/org/apache/harmony/pack200/bytecode/CPRef.java (working copy) @@ -26,6 +26,7 @@ protected CPNameAndType nameAndType; transient int nameAndTypeIndex; + private String resolvedComparisonString = null; public CPRef(byte type, CPClass className, CPNameAndType descriptor) { super(type); @@ -90,6 +91,10 @@ // If we get here, the receiver has been resolved; there // is a different sort order. + if(resolvedComparisonString != null) { + return resolvedComparisonString; + } + StringBuffer result = new StringBuffer(); // Pad all numbers to 6 digits so they sort correctly. int padLength = 6; @@ -105,7 +110,8 @@ result.append('0'); } result.append("" + nameAndTypeIndex); - return result.toString(); + resolvedComparisonString = result.toString(); + return resolvedComparisonString; } public String toString() { Index: main/java/org/apache/harmony/pack200/bytecode/InnerClassesAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/InnerClassesAttribute.java (revision 640642) +++ main/java/org/apache/harmony/pack200/bytecode/InnerClassesAttribute.java (working copy) @@ -42,7 +42,7 @@ int inner_class_access_flags = -1; public InnerClassesEntry(IcTuple icTuple) { - this(icTuple.C, icTuple.C2, icTuple.N, icTuple.F); + this(icTuple.getC(), icTuple.getC2(), icTuple.getN(), icTuple.getF()); } public InnerClassesEntry(String innerString, String outerString, String nameString, int flags) {