Index: main/java/org/apache/harmony/pack200/Segment.java =================================================================== --- main/java/org/apache/harmony/pack200/Segment.java (revision 618493) +++ main/java/org/apache/harmony/pack200/Segment.java (working copy) @@ -21,6 +21,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.zip.GZIPInputStream; @@ -68,8 +71,6 @@ /** - * TODO: Do we need this method now we have Archive as the main entry point? - * * Decode a segment from the given input stream. This does not attempt to * re-assemble or export any class files, but it contains enough information * to be able to re-assemble class files by external callers. @@ -86,6 +87,19 @@ public static Segment parse(InputStream in) throws IOException, Pack200Exception { Segment segment = new Segment(); + // See if file is GZip compressed + if (!in.markSupported()) { + in = new BufferedInputStream(in); + if (!in.markSupported()) + throw new IllegalStateException(); + } + in.mark(2); + if (((in.read() & 0xFF) | (in.read() & 0xFF) << 8) == GZIPInputStream.GZIP_MAGIC) { + in.reset(); + in = new BufferedInputStream(new GZIPInputStream(in)); + } else { + in.reset(); + } segment.parseSegment(in); return segment; } @@ -128,7 +142,14 @@ .getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, AttributeLayout.CONTEXT_CLASS); if (SOURCE_FILE.matches(classBands.getClassFlags()[classNum])) { - String fileName = fullName.substring(i) + ".java"; + int firstDollar = SegmentUtils.indexOfFirstDollar(fullName); + String fileName = null; + + if(firstDollar > -1 && (i <= firstDollar)) { + fileName = fullName.substring(i, firstDollar) + ".java"; + } else { + fileName = fullName.substring(i) + ".java"; + } classFile.attributes = new Attribute[] { (Attribute) cp .add(new SourceFileAttribute(fileName)) }; } else { @@ -156,40 +177,54 @@ cfMethods[i] = cp.add(new CPMethod(classBands.getMethodDescr()[classNum][i], classBands.getMethodFlags()[classNum][i], classBands.getMethodAttributes()[classNum][i])); } - // TODO: maybe this is a better place to add ic_relevant? - // This seems like the right thing to do. - boolean addedClasses = false; + + // add inner class attribute (if required) + boolean addInnerClassesAttr = false; + IcTuple[] ic_local = getClassBands().getIcLocal()[classNum]; + boolean ic_local_sent = false; + if(ic_local != null) { + ic_local_sent = true; + } InnerClassesAttribute innerClassesAttribute = new InnerClassesAttribute("InnerClasses"); IcTuple[] ic_relevant = getIcBands().getRelevantIcTuples(fullName, cp); + IcTuple[] ic_stored = computeIcStored(ic_local, ic_relevant); + for(int index = 0; index < ic_stored.length; index++) { + String innerClassString = ic_stored[index].thisClassString(); + String outerClassString = ic_stored[index].outerClassString(); + String simpleClassName = ic_stored[index].simpleClassName(); - for(int index = 0; index < ic_relevant.length; index++) { - String innerClassString = ic_relevant[index].thisClassString(); - String outerClassString = ic_relevant[index].outerClassString(); - String simpleClassName = ic_relevant[index].simpleClassName(); - CPClass innerClass = null; CPUTF8 innerName = null; CPClass outerClass = null; - if(ic_relevant[index].isAnonymous()) { + if(ic_stored[index].isAnonymous()) { innerClass = new CPClass(innerClassString); } else { innerClass = new CPClass(innerClassString); innerName = new CPUTF8(simpleClassName, ClassConstantPool.DOMAIN_ATTRIBUTEASCIIZ); } - // TODO: I think we need to worry about if the - // OUTER class is a member or not - not the - // ic_relevant itself. -// if(ic_relevant[index].isMember()) { + if(ic_stored[index].isMember()) { outerClass = new CPClass(outerClassString); -// } + } - int flags = ic_relevant[index].F; + int flags = ic_stored[index].F; innerClassesAttribute.addInnerClassesEntry(innerClass, outerClass, innerName, flags); - addedClasses = true; + addInnerClassesAttr = true; } - if(addedClasses) { + // If ic_local is sent and it's empty, don't add + // the inner classes attribute. + if(ic_local_sent && (ic_local.length == 0)) { + addInnerClassesAttr = false; + } + + // If ic_local is not sent and ic_relevant is empty, + // don't add the inner class attribute. + if(!ic_local_sent && (ic_relevant.length == 0)) { + addInnerClassesAttr = false; + } + + if(addInnerClassesAttr) { // Need to add the InnerClasses attribute to the // existing classFile attributes. Attribute[] originalAttrs = classFile.attributes; @@ -225,6 +260,54 @@ /** + * Given an ic_local and an ic_relevant, use them to + * calculate what should be added as ic_stored. + * @param ic_local IcTuple[] array of local transmitted tuples + * @param ic_relevant IcTuple[] array of relevant tuples + * @return IcTuple[] array of tuples to be stored. If ic_local + * is null or empty, the values returned may not be correct. + * The caller will have to determine if this is the case. + */ + private IcTuple[] computeIcStored(IcTuple[] ic_local, IcTuple[] ic_relevant) { + List result = new ArrayList(); + List resultCopy = new ArrayList(); + List localList = new ArrayList(); + List relevantList = new ArrayList(); + if(ic_local != null) { + // If ic_local is null, this code doesn't get + // executed - which means the list ends up being + // ic_relevant. + for(int index=0; index < ic_local.length; index++) { + result.add(ic_local[index]); + resultCopy.add(ic_local[index]); + localList.add(ic_local[index]); + } + } + for(int index=0; index < ic_relevant.length; index++) { + result.add(ic_relevant[index]); + resultCopy.add(ic_relevant[index]); + relevantList.add(ic_relevant[index]); + } + + // Since we're removing while iterating, iterate over + // a copy. + Iterator it = resultCopy.iterator(); + + while(it.hasNext()) { + IcTuple tuple = (IcTuple)it.next(); + if(localList.contains(tuple) && relevantList.contains(tuple)) { + while(result.remove(tuple)) {}; + } + } + IcTuple[] resultArray = new IcTuple[result.size()]; + for(int index=0; index < resultArray.length; index++) { + resultArray[index] = (IcTuple)result.get(index); + } + return resultArray; + } + + + /** * This performs the actual work of parsing against a non-static instance of * Segment. * Index: main/java/org/apache/harmony/pack200/IcBands.java =================================================================== --- main/java/org/apache/harmony/pack200/IcBands.java (revision 618493) +++ main/java/org/apache/harmony/pack200/IcBands.java (working copy) @@ -29,8 +29,6 @@ * Pack200 Inner Class Bands */ public class IcBands extends BandSet { - - private IcTuple[] icAll; private String[] cpUTF8; @@ -92,14 +90,12 @@ List relevantTuples = new ArrayList(); IcTuple[] allTuples = getIcTuples(); int allTuplesSize = allTuples.length; - SegmentUtils.debug("-------\nRelevant() " + className); for(int index=0; index < allTuplesSize; index++) { if(allTuples[index].outerClassString().equals(className)) { relevantTuples.add(allTuples[index]); } } - SegmentUtils.debug("self halt"); List classPoolClasses = cp.allClasses(); boolean changed = true; // For every class in both ic_this_class and cp, @@ -109,40 +105,35 @@ changed = false; for(int allTupleIndex=0; allTupleIndex < allTuplesSize; allTupleIndex++) { Iterator it = classPoolClasses.iterator(); - SegmentUtils.debug("\n\n----\nLooking through class pool for: " + allTuples[allTupleIndex].thisClassString()); while(it.hasNext()) { CPClass classInPool = (CPClass)it.next(); String poolClassName = classInPool.name; - SegmentUtils.debug(" " + poolClassName); if(poolClassName.equals(allTuples[allTupleIndex].thisClassString())) { // If the tuple isn't already in there, then add it - SegmentUtils.debug(" -> match"); if(relevantTuples.indexOf(allTuples[allTupleIndex]) == -1) { - SegmentUtils.debug(" -> added"); relevantTuples.add(allTuples[allTupleIndex]); changed = true; } } - // TODO: is this right? - if(poolClassName.equals(allTuples[allTupleIndex].outerClassString())) { - // If the tuple isn't already in there, then add it - SegmentUtils.debug(" -> omatch"); - if(relevantTuples.indexOf(allTuples[allTupleIndex]) == -1) { - SegmentUtils.debug(" -> oadded"); - relevantTuples.add(allTuples[allTupleIndex]); - changed = true; - } - } } } } - IcTuple[] result = new IcTuple[relevantTuples.size()]; - for(int index=0; index < result.length; index++) { - result[index] = (IcTuple)relevantTuples.get(index); - SegmentUtils.debug("Returning relevantTuple: " + result[index].thisClassString()); + // Now order the result as a subsequence of ic_all + IcTuple[] orderedRelevantTuples = new IcTuple[relevantTuples.size()]; + int orderedRelevantIndex = 0; + for(int index=0; index < allTuplesSize; index++) { + if(relevantTuples.contains(allTuples[index])) { + orderedRelevantTuples[orderedRelevantIndex] = allTuples[index]; + orderedRelevantIndex++; + } } - return result; + if(orderedRelevantIndex != orderedRelevantTuples.length) { + // This should never happen. If it does, we have a + // logic error in the ordering code. + throw new Error("Missing a tuple when ordering them"); + } + return orderedRelevantTuples; } } \ No newline at end of file Index: main/java/org/apache/harmony/pack200/IcTuple.java =================================================================== --- main/java/org/apache/harmony/pack200/IcTuple.java (revision 618493) +++ main/java/org/apache/harmony/pack200/IcTuple.java (working copy) @@ -102,7 +102,8 @@ if(predicted()) { return C; } else { - // TODO: this may not be right. + // TODO: this may not be right. What if I + // get a class like Foo#Bar$Baz$Bug? return C2 + "$" + N; } } @@ -146,26 +147,15 @@ member = false; } if(index + 1 != lastPosition) { + // TODO: might need more logic to handle + // classes with separators of non-$ characters + // (ie Foo#Bar) cachedOuterClassString += '$'; } } - // Now special-case: if the last part of the outer - // class name is all digits, then the cachedOuterClassString - // is null (an anonymous outer class). If the cachedInnerClassString - // is all digits, then the cachedInnerClassString is null (an - // anonymous inner class). - // TODO: Don't know about this - we might need to - // do this later on (after we've determined what's - // anonymous and what isn't) so we point to the right - // class file entries. -// if(isAllDigits(nameComponents[lastPosition - 1])) { -// cachedOuterClassString = null; -// anonymous = false; -// } if(isAllDigits(cachedSimpleClassName)) { anonymous = true; member = false; -// cachedSimpleClassName = C; } } Index: main/java/org/apache/harmony/pack200/SegmentConstantPool.java =================================================================== --- main/java/org/apache/harmony/pack200/SegmentConstantPool.java (revision 618493) +++ main/java/org/apache/harmony/pack200/SegmentConstantPool.java (working copy) @@ -178,8 +178,8 @@ * String [position 2, 1st instance of String] * Object [position 3, 1st instance of Object] * Object [position 4, 2nd instance of Object] - * then classSpecificPoolEntryIndex(..., "Object", 2, false) will - * answer 4. classSpecificPoolEntryIndex(..., "String", 0, false) + * then matchSpecificPoolEntryIndex(..., "Object", 2, false) will + * answer 4. matchSpecificPoolEntryIndex(..., "String", 0, false) * will answer 1. * * @param nameArray Array of Strings against which the compareString is tested @@ -220,9 +220,6 @@ } // We didn't return in the for loop, so the desiredMatch // with desiredIndex must not exist in the array. - if(secondaryCompareRegex.equals("^.*")) { - SegmentUtils.debug("self halt"); - } return -1; } Index: main/java/org/apache/harmony/pack200/bytecode/CPMethodRef.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CPMethodRef.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/CPMethodRef.java (working copy) @@ -18,18 +18,15 @@ public class CPMethodRef extends CPRef { - protected CPClass className = null; - protected CPNameAndType descriptor = null; - public CPMethodRef(String className, String descriptor) { super(ConstantPoolEntry.CP_Methodref, className, descriptor); this.className = new CPClass(className); - this.descriptor = new CPNameAndType(descriptor); + this.nameAndType = new CPNameAndType(descriptor); this.domain = ClassConstantPool.DOMAIN_METHOD; } protected ClassFileEntry[] getNestedClassFileEntries() { - return new ClassFileEntry[] { className, descriptor }; + return new ClassFileEntry[] { className, nameAndType }; } } Index: main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (working copy) @@ -21,7 +21,6 @@ import java.util.List; import org.apache.harmony.pack200.Segment; -import org.apache.harmony.pack200.SegmentUtils; public class ClassConstantPool { @@ -68,7 +67,6 @@ classPoolSet.add(entry); if (!entries.contains(entry)) { entries.add(entry); - // TODO This will be a bugger when they're sorted. if (entry instanceof CPLong ||entry instanceof CPDouble) entries.add(entry); //these get 2 slots because of their size } @@ -105,11 +103,7 @@ } public void resolve(Segment segment) { - SegmentUtils.debug("\n\nResolving (Segment.resolve(Segment)"); - // TODO: Be careful here, you're obliterating the original entries. - // In an ideal world, you wouldn't actually add to it unless you're - // sure. - entries = new ArrayList(); + entries = new ArrayList(); Iterator sortedIterator = classPoolSet.iterator(); while(sortedIterator.hasNext()) { ConstantPoolEntry entry = (ConstantPoolEntry)sortedIterator.next(); @@ -152,6 +146,21 @@ if (entry instanceof CPLong ||entry instanceof CPDouble) entries.add(entry); //these get 2 slots because of their size } + + // Now that the indices have been re-sorted, need + // to re-resolve to update references. This should + // not add any new entries this time through. + it = entries.iterator(); + while(it.hasNext()) { + ClassFileEntry entry = (ClassFileEntry)it.next(); + entry.resolve(this); + } + // Also need to re-resolve the others. + it = others.iterator(); + while(it.hasNext()) { + ClassFileEntry entry = (ClassFileEntry)it.next(); + entry.resolve(this); + } } /** Index: main/java/org/apache/harmony/pack200/bytecode/BCIRenumberedAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/BCIRenumberedAttribute.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/BCIRenumberedAttribute.java (working copy) @@ -20,8 +20,6 @@ import java.io.IOException; import java.util.List; -import org.apache.harmony.pack200.SegmentUtils; - public abstract class BCIRenumberedAttribute extends Attribute { protected boolean renumbered = false; @@ -54,9 +52,7 @@ */ public void renumber(List byteCodeOffsets) { if(renumbered) { - SegmentUtils.debug("Trying to renumber something renumbered"); - return; -// throw new Error("Trying to renumber a line number table that has already been renumbered"); + throw new Error("Trying to renumber a line number table that has already been renumbered"); } renumbered = true; int[] startPCs = getStartPCs(); Index: main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (working copy) @@ -83,8 +83,6 @@ ByteCode byteCode = (ByteCode)byteCodes.get(i); byteCode.applyByteCodeTargetFixup(this); } - // TODO: By the time I get here, the input stream - // is somehow confused. } protected int getLength() { Index: main/java/org/apache/harmony/pack200/bytecode/ByteCode.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (working copy) @@ -135,7 +135,8 @@ case 4: // TODO: need to handle wides? - SegmentUtils.debug("Need to handle wides"); + SegmentUtils.debug("Need to handle wides"); + throw new Error("Instruction argument not handled"); // figure out and if so, handle and put a break here. // break; Index: main/java/org/apache/harmony/pack200/bytecode/CPRef.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CPRef.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/CPRef.java (working copy) @@ -24,7 +24,7 @@ CPClass className; transient int classNameIndex; - protected final CPNameAndType nameAndType; + protected CPNameAndType nameAndType; transient int nameAndTypeIndex; public CPRef(byte type, String className, String descriptor) { Index: main/java/org/apache/harmony/pack200/bytecode/forms/NewInitMethodRefForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/NewInitMethodRefForm.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/forms/NewInitMethodRefForm.java (working copy) @@ -54,15 +54,6 @@ nested = new ClassFileEntry[] { globalPool.getInitMethodPoolEntry(SegmentConstantPool.CP_METHOD, offset, context(operandManager)) }; - if(nested[0] == null) { - // One class in JNDI isn't finding its - // method. Not sure why. - // TODO: find out why. - // org/apache/harmony/security/asn1/ASN1Type - byteCode.setNested(new ClassFileEntry[]{}); - byteCode.setNestedPositions(new int[][] {{}}); - return; - } byteCode.setNested(nested); byteCode.setNestedPositions(new int[][] {{0, 2}}); } Index: main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java (working copy) @@ -251,7 +251,7 @@ byteCodeArray[186] = new NoArgumentForm(186, "xxxunusedxxx"); byteCodeArray[187] = new NewClassRefForm(187, "new", new int[] {187, -1, -1}); byteCodeArray[188] = new ByteForm(188, "newarray", new int[] {188, -1}); - byteCodeArray[189] = new NewClassRefForm(189, "anewarray", new int[] {189, -1, -1}); + byteCodeArray[189] = new ClassRefForm(189, "anewarray", new int[] {189, -1, -1}); byteCodeArray[190] = new NoArgumentForm(190, "arraylength"); byteCodeArray[191] = new NoArgumentForm(191, "athrow"); byteCodeArray[192] = new ClassRefForm(192, "checkcast", new int[] {192, -1, -1}); Index: main/java/org/apache/harmony/pack200/bytecode/forms/MultiANewArrayForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/MultiANewArrayForm.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/forms/MultiANewArrayForm.java (working copy) @@ -22,11 +22,12 @@ /** * This class implements the byte code form for the * multianewarray instruction. It has a class reference - * and a byte operand. Like other NewClassRefForms, it - * keeps track of the last object created so other New - * forms can make use of this information. + * and a byte operand. + * + * MultiANewArrayForms (like other anewarray + * forms) do not track the last new(). */ -public class MultiANewArrayForm extends NewClassRefForm { +public class MultiANewArrayForm extends ClassRefForm { public MultiANewArrayForm(int opcode, String name, int[] rewrite) { Index: main/java/org/apache/harmony/pack200/bytecode/InnerClassesAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/InnerClassesAttribute.java (revision 618493) +++ main/java/org/apache/harmony/pack200/bytecode/InnerClassesAttribute.java (working copy) @@ -23,7 +23,6 @@ import java.util.List; import org.apache.harmony.pack200.IcTuple; -import org.apache.harmony.pack200.SegmentUtils; public class InnerClassesAttribute extends Attribute { @@ -59,11 +58,6 @@ * CPClass and CPUTF8 objects. */ public void resolve(ClassConstantPool pool) { - SegmentUtils.debug("----"); - SegmentUtils.debug("inner_class_info: " + inner_class_info); - SegmentUtils.debug("inner_class_name: " + inner_class_name); - SegmentUtils.debug("outer_class_info: " + outer_class_info); - if(inner_class_info != null) { inner_class_info.resolve(pool); inner_class_info_index = pool.indexOf(inner_class_info); Index: main/java/org/apache/harmony/pack200/SegmentUtils.java =================================================================== --- main/java/org/apache/harmony/pack200/SegmentUtils.java (revision 618493) +++ main/java/org/apache/harmony/pack200/SegmentUtils.java (working copy) @@ -121,38 +121,23 @@ } /** - * Given a String classX (the name of a class) and the - * collection of inner class tuples ic_all, answer - * ic_relevant(classX) - * @param classX String class name - * @param ic_all ICTuple[] all the inner class tuples - * @return ICTuple[] all the relevant tuples sorted as in + * Answer the index of the first character <= '$' + * in the parameter. This is used instead of indexOf('$') + * because inner classes may be separated by any character + * <= '$' (in other words, Foo#Bar is as valid as Foo$Bar). + * If no $ character is found, answer -1. + * @param string String to search for $ + * @return first index of $ character, or -1 if not found */ - public static IcTuple[] icRelevant(String classX, IcTuple[] ic_all) { - return null; - } - - public static boolean isRelevant(String outerClass, IcTuple tuple) { - if(tuple.C.equals(outerClass)) { - // If the outer class name is explicitly - // specified and it's the correct one, the - // tuple is relevant. - return true; + public static int indexOfFirstDollar(String string) { + for(int index=0; index