Index: main/java/org/apache/harmony/pack200/ClassBands.java =================================================================== --- main/java/org/apache/harmony/pack200/ClassBands.java (revision 598351) +++ main/java/org/apache/harmony/pack200/ClassBands.java (working copy) @@ -20,10 +20,10 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import org.apache.harmony.pack200.IcBands.ICTuple; +import org.apache.harmony.pack200.bytecode.Attribute; import org.apache.harmony.pack200.bytecode.CPClass; import org.apache.harmony.pack200.bytecode.CPUTF8; import org.apache.harmony.pack200.bytecode.ConstantValueAttribute; @@ -999,6 +999,31 @@ return fieldFlags; } + /** + * Answer an ArrayList of the LineNumberTables corresponding to all classes. + * If a class doesn't have a LineNumberTable, the corresponding element in this + * list will be null. + * @return ArrayList + */ + // TODO: the class file spec allows >1 LineNumberTable per method. Does Pack200 spec fold them all into one? (If not, need to handle that case.) + public ArrayList getLineNumberAttributes() { + ArrayList lineNumberList = new ArrayList(); + for(int classIndex=0; classIndex < codeAttributes.length; classIndex++) { + boolean foundLineNumberTable = false; + for(int attributeIndex = 0; attributeIndex < codeAttributes[classIndex].size(); attributeIndex++) { + Attribute attribute = (Attribute)codeAttributes[classIndex].get(attributeIndex); + if(attribute.getClass() == LineNumberTableAttribute.class) { + foundLineNumberTable = true; + lineNumberList.add(attribute); + } + } + if(!foundLineNumberTable) { + lineNumberList.add(null); + } + } + return lineNumberList; + } + public ArrayList[][] getMethodAttributes() { return methodAttributes; } Index: main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (revision 598351) +++ main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (working copy) @@ -21,8 +21,10 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; + import org.apache.harmony.pack200.Pack200Exception; import org.apache.harmony.pack200.Segment; +import org.apache.harmony.pack200.SegmentUtils; public class ClassConstantPool { @@ -74,7 +76,7 @@ } public void resolve(Segment segment) { - System.out.println("\n\nResolving (Segment.resolve(Segment)"); + SegmentUtils.debug("\n\nResolving (Segment.resolve(Segment)"); HashMap sortMap = new HashMap(); List cpAll = null; // TODO: HACK - this is a 1.5 api. @@ -101,7 +103,7 @@ } } for(int xindex=0; xindex < sortedList.size(); xindex++) { - System.out.println(sortedList.get(xindex)); + SegmentUtils.debug(sortedList.get(xindex).toString()); } resolve(); } Index: main/java/org/apache/harmony/pack200/bytecode/OperandManager.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/OperandManager.java (revision 598351) +++ main/java/org/apache/harmony/pack200/bytecode/OperandManager.java (working copy) @@ -166,14 +166,6 @@ return bcInitRef[bcInitRefIndex++]; } - public static void main(String args[]) { - int foo[] = {1, 172, 3, 4}; - OperandManager op = new OperandManager(foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo, foo); - for(int index=0; index < 4; index++) { - System.out.println(op.nextByte()); - } - } - public void setSegment(Segment segment) { this.segment = segment; } Index: main/java/org/apache/harmony/pack200/bytecode/LineNumberTableAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/LineNumberTableAttribute.java (revision 598351) +++ main/java/org/apache/harmony/pack200/bytecode/LineNumberTableAttribute.java (working copy) @@ -18,12 +18,17 @@ import java.io.DataOutputStream; import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import org.apache.harmony.pack200.SegmentUtils; + public class LineNumberTableAttribute extends Attribute { private int line_number_table_length; private int[] start_pcs; private int[] line_numbers; + private boolean renumbered = false; public LineNumberTableAttribute(int line_number_table_length, int[] start_pcs, int[] line_numbers) { super("LineNumberTable"); @@ -44,8 +49,38 @@ } } + /* (non-Javadoc) + * @see org.apache.harmony.pack200.bytecode.ClassFileEntry#toString() + */ public String toString() { return "LineNumberTable: " + line_number_table_length + " lines"; } + /* (non-Javadoc) + * @see org.apache.harmony.pack200.bytecode.Attribute#resolve(org.apache.harmony.pack200.bytecode.ClassConstantPool) + */ + protected void resolve(ClassConstantPool pool) { + pool.add(getAttributeName()); + super.resolve(pool); + } + + /** + * In Pack200, line number tables are BCI renumbered. + * This method takes the byteCodeOffsets (which is + * a List of Integers specifying the offset in the + * byte code array of each instruction) and updates the + * start_pcs so that it points to the instruction index + * itself, not the BCI renumbering of the instruction. + * + * @param byteCodeOffsets List of Integer offsets of the bytecode array + */ + public void renumberLineNumberTable(List byteCodeOffsets) { + if(renumbered) { + throw new Error("Trying to renumber a line number table that has already been renumbered"); + } + renumbered = true; + for(int index=0; index < line_numbers.length; index++) { + start_pcs[index] = ((Integer)byteCodeOffsets.get(start_pcs[index])).intValue(); + } + } } Index: main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (revision 598351) +++ main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (working copy) @@ -23,6 +23,7 @@ import java.util.List; import org.apache.harmony.pack200.Segment; +import org.apache.harmony.pack200.SegmentUtils; public class CodeAttribute extends Attribute { public List attributes = new ArrayList(); @@ -30,6 +31,7 @@ public int codeLength; public List exceptionTable = new ArrayList(); // of ExceptionTableEntry // instances + public List byteCodeOffsets = new ArrayList(); public int maxLocals; public int maxStack; @@ -39,11 +41,25 @@ this.maxLocals = maxLocals; this.maxStack = maxStack; this.codeLength = 0; + byteCodeOffsets.add(new Integer(0)); for (int i = 0; i < codePacked.length; i++) { ByteCode byteCode = ByteCode.getByteCode(codePacked[i] & 0xff); byteCode.extractOperands(operandManager, segment); byteCodes.add(byteCode); this.codeLength += byteCode.getLength(); + int lastBytecodePosition = ((Integer)byteCodeOffsets.get(byteCodeOffsets.size() - 1)).intValue(); + // This code assumes all multiple byte bytecodes are + // replaced by a single-byte bytecode followed by + // another bytecode. + if(byteCode.hasMultipleByteCodes()) { + byteCodeOffsets.add(new Integer(lastBytecodePosition + 1)); + } + // I've already added the first element (at 0) before + // entering this loop, so make sure I don't add one + // after the last element. + if(i < (codePacked.length - 1)) { + byteCodeOffsets.add(new Integer(lastBytecodePosition + byteCode.getLength())); + } } } @@ -72,6 +88,7 @@ Iterator it = attributes.iterator(); while (it.hasNext()) { Attribute attribute = (Attribute) it.next(); + SegmentUtils.debug("CodeAttribute resolving " + attribute); attribute.resolve(pool); } it = byteCodes.iterator(); Index: main/java/org/apache/harmony/pack200/bytecode/ByteCode.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (revision 598351) +++ main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (working copy) @@ -18,7 +18,9 @@ import java.io.DataOutputStream; import java.io.IOException; + import org.apache.harmony.pack200.Segment; +import org.apache.harmony.pack200.SegmentUtils; import org.apache.harmony.pack200.bytecode.forms.ByteCodeForm; public class ByteCode extends ClassFileEntry { @@ -131,12 +133,12 @@ case 4: // TODO: need to handle wides? - System.out.println("Need to handle wides"); + SegmentUtils.debug("Need to handle wides"); // figure out and if so, handle and put a break here. // break; default: - System.out.println("Unhandled resolve " + this); + SegmentUtils.debug("Unhandled resolve " + this); } } } @@ -181,7 +183,7 @@ */ public void setOperandInt(int operand, int position) { int firstOperandIndex = getByteCodeForm().firstOperandIndex(); - int byteCodeFormLength = getByteCodeForm().operandLength(); + int byteCodeFormLength = getByteCodeForm().getRewrite().length; if (firstOperandIndex < 1) { // No operand rewriting permitted for this bytecode throw new Error("Trying to rewrite " + this + " that has no rewrite"); @@ -260,4 +262,16 @@ public int[] getNestedPosition(int index) { return getNestedPositions()[index]; } + + /** + * This method will answer true if the receiver is + * a multi-bytecode instruction (such as + * aload0_putfield_super); otherwise, it will answer + * false. + * + * @return boolean true if multibytecode, false otherwise + */ + public boolean hasMultipleByteCodes() { + return getByteCodeForm().hasMultipleByteCodes(); + } } Index: main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java (revision 598351) +++ main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java (working copy) @@ -541,7 +541,30 @@ return false; } + /** + * This method will answer true if the receiver is + * a multi-bytecode instruction (such as + * aload0_putfield_super); otherwise, it will answer + * false. + * + * @return boolean true if multibytecode, false otherwise + */ + public boolean hasMultipleByteCodes() { + if(rewrite.length > 1) { + // Currently, all multi-bytecode instructions + // begin with aload_0, so this is how we test. + if(rewrite[0] == 42) { + // If there's an instruction (not a negative + // number, which is an operand) after the + // aload_0, it's a multibytecode instruction. + return(rewrite[1] > 0); + } + } + return false; + } + + /** * When passed a byteCode, an OperandTable and a * SegmentConstantPool, this method will set the * rewrite of the byteCode appropriately. Index: main/java/org/apache/harmony/pack200/SegmentUtils.java =================================================================== --- main/java/org/apache/harmony/pack200/SegmentUtils.java (revision 598351) +++ main/java/org/apache/harmony/pack200/SegmentUtils.java (working copy) @@ -92,4 +92,19 @@ private SegmentUtils() { // Intended to be a helper class } + + /** + * This is a debugging message to aid the developer in writing this + * class. If the property 'debug.pack200' is set, this will + * generate messages to stderr; otherwise, it will be silent. + * + * @param message + * @deprecated this may be removed from production code + */ + public static void debug(String message) { + if (System.getProperty("debug.pack200") != null) { + System.err.println(message); + } + } + } Index: main/java/org/apache/harmony/pack200/BcBands.java =================================================================== --- main/java/org/apache/harmony/pack200/BcBands.java (revision 598351) +++ main/java/org/apache/harmony/pack200/BcBands.java (working copy) @@ -24,6 +24,7 @@ import org.apache.harmony.pack200.bytecode.ByteCode; import org.apache.harmony.pack200.bytecode.CodeAttribute; +import org.apache.harmony.pack200.bytecode.LineNumberTableAttribute; import org.apache.harmony.pack200.bytecode.OperandManager; /** @@ -360,6 +361,12 @@ CodeAttribute attr = new CodeAttribute(maxStack, maxLocal, methodByteCodePacked[c][m], segment, operandManager); methodAttributes[c][m].add(attr); + // Fix up the line numbers + LineNumberTableAttribute lineNumberTable = (LineNumberTableAttribute)segment.getClassBands().getLineNumberAttributes().get(i); + if(null != lineNumberTable) { + attr.attributes.add(lineNumberTable); + lineNumberTable.renumberLineNumberTable(attr.byteCodeOffsets); + } i++; } }