Index: main/java/org/apache/harmony/pack200/bytecode/OperandManager.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/OperandManager.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/OperandManager.java (working copy) @@ -28,6 +28,8 @@ */ public class OperandManager { + int[] bcCaseCount; + int[][] bcCaseValue; int[] bcByte; int[] bcShort; int[] bcLocal; @@ -47,6 +49,8 @@ int[] bcSuperMethod; int[] bcInitRef; + int bcCaseCountIndex = 0; + int bcCaseValueIndex = 0; int bcByteIndex = 0; int bcShortIndex = 0; int bcLocalIndex = 0; @@ -72,7 +76,9 @@ String superClass = null; String newClass = null; - public OperandManager(int[] bcByte, int[] bcShort, int[] bcLocal, int[] bcLabel, int[] bcIntRef, int[] bcFloatRef, int[] bcLongRef, int[] bcDoubleRef, int[] bcStringRef, int[] bcClassRef, int[] bcFieldRef, int[] bcMethodRef, int[] bcIMethodRef, int[] bcThisField, int[] bcSuperField, int[] bcThisMethod, int[] bcSuperMethod, int[] bcInitRef) { + public OperandManager(int[] bcCaseCount, int[][] bcCaseValue, int[] bcByte, int[] bcShort, int[] bcLocal, int[] bcLabel, int[] bcIntRef, int[] bcFloatRef, int[] bcLongRef, int[] bcDoubleRef, int[] bcStringRef, int[] bcClassRef, int[] bcFieldRef, int[] bcMethodRef, int[] bcIMethodRef, int[] bcThisField, int[] bcSuperField, int[] bcThisMethod, int[] bcSuperMethod, int[] bcInitRef) { + this.bcCaseCount = bcCaseCount; + this.bcCaseValue = bcCaseValue; this.bcByte = bcByte; this.bcShort = bcShort; this.bcLocal = bcLocal; @@ -94,6 +100,14 @@ this.bcInitRef = bcInitRef; } + public int nextCaseCount() { + return bcCaseCount[bcCaseCountIndex++]; + } + + public int[] nextCaseValues() { + return bcCaseValue[bcCaseValueIndex++]; + } + public int nextByte() { return bcByte[bcByteIndex++]; } Index: main/java/org/apache/harmony/pack200/bytecode/LocalVariableTableAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/LocalVariableTableAttribute.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/LocalVariableTableAttribute.java (working copy) @@ -90,8 +90,12 @@ public void renumber(List byteCodeOffsets) { // First fix up the start_pcs super.renumber(byteCodeOffsets); + // lengths are BRANCH5 encoded, not BCI-encoded. + // In other words - renumber(x) - renumber(x0)? + // Add the offset to the value? // Next fix up the lengths - int maxLength = ((Integer)byteCodeOffsets.get(byteCodeOffsets.size() - 1)).intValue(); + int lastInstruction = ((Integer)byteCodeOffsets.get(byteCodeOffsets.size() - 1)).intValue(); + int maxLength = lastInstruction + 1; for(int index=0; index < lengths.length; index++) { // Need to special case when the length is greater than the size int revisedLength = -1; @@ -100,7 +104,7 @@ // end of the byte code offsets. Need to determine which this is. if(encodedLength == byteCodeOffsets.size()) { // Pointing to one past the end of the byte code array - revisedLength = maxLength - start_pcs[index] + 1; + revisedLength = maxLength - start_pcs[index]; } else { // We're indexed into the byte code array revisedLength = ((Integer)byteCodeOffsets.get(encodedLength)).intValue(); Index: main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (working copy) @@ -46,7 +46,7 @@ // Setting the offset must happen before extracting operands // because label bytecodes need to know their offsets. byteCode.setByteCodeIndex(i); - byteCode.extractOperands(operandManager, segment); + byteCode.extractOperands(operandManager, segment, codeLength); byteCodes.add(byteCode); codeLength += byteCode.getLength(); int lastBytecodePosition = ((Integer) byteCodeOffsets Index: main/java/org/apache/harmony/pack200/bytecode/ByteCode.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (working copy) @@ -36,7 +36,7 @@ private int[] rewrite; private int byteCodeOffset = -1; - private int byteCodeTarget = -1; + private int[] byteCodeTargets = null; protected ByteCode(int opcode) { this(opcode, ClassFileEntry.NONE); @@ -69,14 +69,13 @@ return true; } - public void extractOperands(OperandManager operandManager, Segment segment) { + public void extractOperands(OperandManager operandManager, Segment segment, int codeLength) { // Given an OperandTable, figure out which operands // the receiver needs and stuff them in operands. // Later on the operands can be rewritten (But that's // later, not now). - ByteCodeForm currentByteCodeForm = getByteCodeForm(); - currentByteCodeForm.setByteCodeOperands(this, operandManager); + currentByteCodeForm.setByteCodeOperands(this, operandManager, codeLength); } protected ByteCodeForm getByteCodeForm() { @@ -131,7 +130,7 @@ break; case 2: - setOperandInt(pool.indexOf(nested[index]), getNestedPosition(index)[0]); + setOperand2Bytes(pool.indexOf(nested[index]), getNestedPosition(index)[0]); break; case 4: @@ -172,7 +171,7 @@ rewrite[index + firstOperandIndex] = operands[index] & 0xFF; } } - + /** * Given an int operand, set the rewrite bytes for * that position and the one immediately following it @@ -184,7 +183,7 @@ * position 0 is the first -1, position 1 is the second -1, * etc. */ - public void setOperandInt(int operand, int position) { + public void setOperand2Bytes(int operand, int position) { int firstOperandIndex = getByteCodeForm().firstOperandIndex(); int byteCodeFormLength = getByteCodeForm().getRewrite().length; if (firstOperandIndex < 1) { @@ -206,12 +205,12 @@ * @param operand int to set the rewrite bytes to * @param position int position of the operands in the rewrite bytes */ - public void setOperandSignedInt(int operand, int position) { + public void setOperandSigned2Bytes(int operand, int position) { if(operand >= 0) { - setOperandInt(operand, position); + setOperand2Bytes(operand, position); } else { int twosComplementOperand = 0x10000 + operand; - setOperandInt(twosComplementOperand, position); + setOperand2Bytes(twosComplementOperand, position); } } @@ -315,31 +314,60 @@ } /** - * Some ByteCodes (in particular, LabelForm bytecodes) - * have to keep track of a byteCodeTarget. This is - * initially an offset in the CodeAttribute array - * relative to the byteCodeOffset, but later gets fixed + * Some ByteCodes (in particular, those with labels) + * have to keep track of byteCodeTargets. These are + * initially offsets in the CodeAttribute array + * relative to the byteCodeOffset, but later get fixed * up to point to the absolute position in the CodeAttribute - * array. This method sets the target. + * array. This method sets the targets. * * @param byteCodeTarget int index in array */ - public void setByteCodeTarget(int byteCodeTarget) { - this.byteCodeTarget = byteCodeTarget; + public void setByteCodeTargets(int[] byteCodeTargets) { + this.byteCodeTargets = byteCodeTargets; } - public int getByteCodeTarget() { - return byteCodeTarget; + public int[] getByteCodeTargets() { + return byteCodeTargets; } /** - * Some ByteCodes (in particular, those with the Label - * form) need to be fixed up after all the bytecodes - * in the CodeAttribute have been added. (This can't + * Some ByteCodes (in particular, those with labels + * need to be fixed up after all the bytecodes in the + * CodeAttribute have been added. (This can't * be done beforehand because the CodeAttribute needs * to be complete before targets can be assigned.) */ public void applyByteCodeTargetFixup(CodeAttribute codeAttribute) { - getByteCodeForm().fixUpByteCodeTarget(this, codeAttribute); + getByteCodeForm().fixUpByteCodeTargets(this, codeAttribute); } + + /** + * Some bytecodes (the ones with variable lengths) can't + * have a static rewrite array - they need the ability to + * update the array. This method permits that. + * + * Note that this should not be called from bytecodes + * which have a static rewrite; use the table in ByteCodeForm + * instead to specify those rewrites. + * + * @param rewrite + */ + public void setRewrite(int[] rewrite) { + this.rewrite = rewrite; + } + + /** + * Some bytecodes (the ones with variable lengths) can't + * have a static rewrite array - they need the ability to + * update the array. This method permits their associated + * bytecode formst to query their rewrite array. + * + * Note that this should not be called from bytecodes + * which have a static rewrite; use the table in ByteCodeForm + * instead to specify those rewrites. + */ + public int[] getRewrite() { + return rewrite; + } } Index: main/java/org/apache/harmony/pack200/bytecode/forms/LabelForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/LabelForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/LabelForm.java (working copy) @@ -50,9 +50,9 @@ /* (non-Javadoc) * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#fixUpByteCodeTarget(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.CodeAttribute) */ - public void fixUpByteCodeTarget(ByteCode byteCode, CodeAttribute codeAttribute) { + public void fixUpByteCodeTargets(ByteCode byteCode, CodeAttribute codeAttribute) { // LabelForms need to fix up the target of label operations - int originalTarget = byteCode.getByteCodeTarget(); + int originalTarget = byteCode.getByteCodeTargets()[0]; int sourceIndex = byteCode.getByteCodeIndex(); int absoluteInstructionTargetIndex = sourceIndex + originalTarget; int targetValue = ((Integer)codeAttribute.byteCodeOffsets.get(absoluteInstructionTargetIndex)).intValue(); @@ -60,7 +60,7 @@ // The operand is the difference between the source instruction // and the destination instruction. // TODO: Probably have to do something other than setOperandInt if this is widened. - byteCode.setOperandSignedInt(targetValue - sourceValue, 0); + byteCode.setOperandSigned2Bytes(targetValue - sourceValue, 0); if(widened) { byteCode.setNestedPositions(new int[][] {{0,4}}); } else { @@ -72,8 +72,8 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { - byteCode.setByteCodeTarget(operandManager.nextLabel()); + OperandManager operandManager, int codeLength) { + byteCode.setByteCodeTargets(new int[] {operandManager.nextLabel()}); // The byte code operands actually get set later - // once we have all the bytecodes - in fixUpByteCodeTarget(). return; Index: main/java/org/apache/harmony/pack200/bytecode/forms/NoArgumentForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/NoArgumentForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/NoArgumentForm.java (working copy) @@ -44,7 +44,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { // Nothing to do for no-argument form } } Index: main/java/org/apache/harmony/pack200/bytecode/forms/ReferenceForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/ReferenceForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/ReferenceForm.java (working copy) @@ -50,7 +50,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.Segment) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { int offset = getOffset(operandManager); try { setNestedEntries(byteCode, operandManager, offset); Index: main/java/org/apache/harmony/pack200/bytecode/forms/NewClassRefForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/NewClassRefForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/NewClassRefForm.java (working copy) @@ -44,7 +44,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ReferenceForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandManager) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { ClassFileEntry[] nested = null; int offset = getOffset(operandManager); if(offset == 0) { Index: main/java/org/apache/harmony/pack200/bytecode/forms/IincForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/IincForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/IincForm.java (working copy) @@ -41,7 +41,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { int local = operandManager.nextLocal(); int constant = operandManager.nextByte(); byteCode.setOperandBytes(new int[]{local, constant}); Index: main/java/org/apache/harmony/pack200/bytecode/forms/IMethodRefForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/IMethodRefForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/IMethodRefForm.java (working copy) @@ -43,7 +43,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { //TODO: implement this. Removed the error message because // it causes failures in the JUnit tests. // throw new Error("Not implemented yet"); Index: main/java/org/apache/harmony/pack200/bytecode/forms/WideForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/WideForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/WideForm.java (working copy) @@ -47,7 +47,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { //TODO: implement this. Removed the error message because // it causes failures in the JUnit tests. // throw new Error("Not implemented yet"); Index: main/java/org/apache/harmony/pack200/bytecode/forms/LocalForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/LocalForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/LocalForm.java (working copy) @@ -48,7 +48,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { byteCode.setOperandBytes(new int[]{operandManager.nextLocal()}); } } Index: main/java/org/apache/harmony/pack200/bytecode/forms/LookupSwitchForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/LookupSwitchForm.java (revision 0) +++ main/java/org/apache/harmony/pack200/bytecode/forms/LookupSwitchForm.java (revision 0) @@ -0,0 +1,91 @@ +package org.apache.harmony.pack200.bytecode.forms; + +import org.apache.harmony.pack200.SegmentUtils; +import org.apache.harmony.pack200.bytecode.ByteCode; +import org.apache.harmony.pack200.bytecode.OperandManager; + +public class LookupSwitchForm extends SwitchForm { + + public LookupSwitchForm(int opcode, String name) { + super(opcode, name); + } + + public LookupSwitchForm(int opcode, String name, int[] rewrite) { + super(opcode, name, rewrite); + } + + public void setByteCodeOperands(ByteCode byteCode, + OperandManager operandManager, int codeLength) { + if(switchCaseCountingBroken) return; + int case_count = operandManager.nextCaseCount(); + int default_pc = operandManager.nextLabel(); + int case_values[] = operandManager.nextCaseValues(); + int case_pcs[] = new int[case_count]; + for(int index=0; index < case_count; index++) { + case_pcs[index] = operandManager.nextLabel(); + } + // All this gets dumped into the rewrite bytes of the + // poor bytecode. + + int[] labelsArray = new int[case_count + 1]; + labelsArray[0] = default_pc; + for(int index=1; index < case_count + 1; index++) { + labelsArray[index] = case_pcs[index-1]; + } + byteCode.setByteCodeTargets(labelsArray); + + // Unlike most byte codes, the LookupSwitch is a + // variable-sized bytecode. Because of this, the + // rewrite array has to be defined here individually + // for each bytecode, rather than in the ByteCodeForm + // class. + + // First, there's the bytecode. Then there are 0-3 + // bytes of padding so that the first (default) + // label is on a 4-byte offset. + int padLength = 3 - (codeLength % 4); + int rewriteSize = 1 + padLength + 4 // defaultbytes + + 4 // npairs + + (4 * case_values.length) + + (4 * case_pcs.length); + + int[] newRewrite = new int[rewriteSize]; + int rewriteIndex = 0; + + // Fill in what we can now + // opcode + newRewrite[rewriteIndex++] = byteCode.getOpcode(); + + // padding + for(int index=0; index < padLength; index++) { + newRewrite[rewriteIndex++] = 0; + } + + // defaultbyte + // This gets overwritten by fixUpByteCodeTargets + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + + // npairs + int npairsIndex = rewriteIndex; + setRewrite4Bytes(case_values.length, npairsIndex, newRewrite); + rewriteIndex += 4; + + // match-offset pairs + // The case_values aren't overwritten, but the + // case_pcs will get overwritten by fixUpByteCodeTargets + for(int index = 0; index < case_values.length; index++) { + // match + setRewrite4Bytes(case_values[index], rewriteIndex, newRewrite); + rewriteIndex += 4; + // offset + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + } + byteCode.setRewrite(newRewrite); + } +} Index: main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/ByteCodeForm.java (working copy) @@ -232,8 +232,8 @@ byteCodeArray[167] = new LabelForm(167, "goto", new int[] {167, -1, -1}); byteCodeArray[168] = new LabelForm(168, "jsr", new int[] {168, -1, -1}); byteCodeArray[169] = new LocalForm(169, "ret", new int[] {169, -1}); - byteCodeArray[170] = new SwitchForm(170, "tableswitch"); - byteCodeArray[171] = new SwitchForm(171, "lookupswitch"); + byteCodeArray[170] = new TableSwitchForm(170, "tableswitch"); + byteCodeArray[171] = new LookupSwitchForm(171, "lookupswitch"); byteCodeArray[172] = new NoArgumentForm(172, "ireturn"); byteCodeArray[173] = new NoArgumentForm(173, "lreturn"); byteCodeArray[174] = new NoArgumentForm(174, "freturn"); @@ -572,10 +572,13 @@ * * @param byteCode ByteCode to be updated (!) * @param operandManager OperandTable from which to draw info - * @param globalPool SegmentConstantPool used to index into + * @param codeLength Length of bytes (excluding this bytecode) + * from the beginning of the method. Used in calculating + * padding for some variable-length bytecodes (such as + * lookupswitch, tableswitch). */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { throw new Error("My subclass should have implemented this"); } @@ -587,7 +590,7 @@ * @param codeAttribute a CodeAttribute used to determine how * the ByteCode should be fixed up. */ - public void fixUpByteCodeTarget(ByteCode byteCode, CodeAttribute codeAttribute) { + public void fixUpByteCodeTargets(ByteCode byteCode, CodeAttribute codeAttribute) { // Most ByteCodeForms don't have any fixing up to do. return; } Index: main/java/org/apache/harmony/pack200/bytecode/forms/ShortForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/ShortForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/ShortForm.java (working copy) @@ -42,7 +42,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { - byteCode.setOperandInt(operandManager.nextShort(), 0); + OperandManager operandManager, int codeLength) { + byteCode.setOperand2Bytes(operandManager.nextShort(), 0); } } Index: main/java/org/apache/harmony/pack200/bytecode/forms/SwitchForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/SwitchForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/SwitchForm.java (working copy) @@ -17,10 +17,13 @@ package org.apache.harmony.pack200.bytecode.forms; import org.apache.harmony.pack200.bytecode.ByteCode; +import org.apache.harmony.pack200.bytecode.CodeAttribute; import org.apache.harmony.pack200.bytecode.OperandManager; -public class SwitchForm extends ByteCodeForm { +public abstract class SwitchForm extends ByteCodeForm { + static boolean switchCaseCountingBroken = true; + public SwitchForm(int opcode, String name) { super(opcode, name); // TODO Auto-generated constructor stub @@ -42,10 +45,94 @@ /* (non-Javadoc) * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ - public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { -//TODO: implement this. Removed the error message because -// it causes failures in the JUnit tests. -// throw new Error("Not implemented yet"); + public abstract void setByteCodeOperands(ByteCode byteCode, + OperandManager operandManager, int codeLength); + + /** + * Given an int operand, set the rewrite bytes for + * the next available operand position and the three + * immediately following it to a highest-byte, + * mid-high, mid-low, low-byte encoding of the operand. + * + * Note that unlike the ByteCode setOperand* operations, this + * starts with an actual bytecode rewrite array (rather than + * a ByteCodeForm prototype rewrite array). Also, this method + * overwrites -1 values in the rewrite array - so if you start + * with an array that looks like: + * {100, -1, -1, -1, -1, 200, -1, -1, -1, -1} then calling + * setRewrite4Bytes(0, rewrite) the first time will convert + * it to: + * {100, 0, 0, 0, 0, 200, -1, -1, -1, -1} + * Calling setRewrite4Bytes(0, rewrite) a second time will + * convert it to: + * {100, 0, 0, 0, 0, 200, 0, 0, 0, 0} + * + * @param operand int to set the rewrite bytes to + * @param rewrite int[] bytes to rewrite + */ + public void setRewrite4Bytes(int operand, int[] rewrite) { + int firstOperandPosition = -1; + + // Find the first -1 in the rewrite array + for(int index=0; index < rewrite.length - 3; index++) { + if((rewrite[index] == -1) + && (rewrite[index+1] == -1) + && (rewrite[index+2] == -1) + && (rewrite[index+3] == -1)) { + firstOperandPosition = index; + break; + } + } + setRewrite4Bytes(operand, firstOperandPosition, rewrite); } + + /** + * This method writes operand directly into the rewrite + * array at index position specified. + * @param operand value to write + * @param absPosition position in array to write. Note that + * this is absolute position in the array, so one can + * overwrite the bytecode if one isn't careful. + * @param rewrite array to write into + */ + public void setRewrite4Bytes(int operand, int absPosition, int[] rewrite) { + if(absPosition < 0) { + throw new Error("Trying to rewrite " + this + " but there is no room for 4 bytes"); + } + + int byteCodeRewriteLength = rewrite.length; + + if(absPosition + 3 > byteCodeRewriteLength) { + throw new Error("Trying to rewrite " + this + " with an int at position " + absPosition + " but this won't fit in the rewrite array"); + } + + rewrite[absPosition] = ((0xFF000000) & operand) >> 24; + rewrite[absPosition + 1] = ((0x00FF0000) & operand) >> 16; + rewrite[absPosition + 2] = ((0x0000FF00) & operand) >> 8; + rewrite[absPosition + 3] = ((0x000000FF) & operand); + } + + /* (non-Javadoc) + * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#fixUpByteCodeTargets(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.CodeAttribute) + */ + public void fixUpByteCodeTargets(ByteCode byteCode, CodeAttribute codeAttribute) { + if(switchCaseCountingBroken) return; + // SwitchForms need to fix up the target of label operations + int[] originalTargets = byteCode.getByteCodeTargets(); + int numberOfLabels = originalTargets.length; + int[] replacementTargets = new int[numberOfLabels]; + + int sourceIndex = byteCode.getByteCodeIndex(); + int sourceValue = ((Integer)codeAttribute.byteCodeOffsets.get(sourceIndex)).intValue(); + for(int index=0; index < numberOfLabels; index++) { + int absoluteInstructionTargetIndex = sourceIndex + originalTargets[index]; + int targetValue = ((Integer)codeAttribute.byteCodeOffsets.get(absoluteInstructionTargetIndex)).intValue(); + replacementTargets[index] = targetValue - sourceValue; + } + int[] rewriteArray = byteCode.getRewrite(); + for(int index=0; index < numberOfLabels; index++) { + setRewrite4Bytes(replacementTargets[index], rewriteArray); + } + } + } Index: main/java/org/apache/harmony/pack200/bytecode/forms/ByteForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/ByteForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/ByteForm.java (working copy) @@ -41,7 +41,7 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { byteCode.setOperandByte(operandManager.nextByte() & 0xFF, 0); } } Index: main/java/org/apache/harmony/pack200/bytecode/forms/MultiANewArrayForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/MultiANewArrayForm.java (revision 603105) +++ main/java/org/apache/harmony/pack200/bytecode/forms/MultiANewArrayForm.java (working copy) @@ -50,10 +50,10 @@ * @see org.apache.harmony.pack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.harmony.pack200.bytecode.ByteCode, org.apache.harmony.pack200.bytecode.OperandTable, org.apache.harmony.pack200.SegmentConstantPool) */ public void setByteCodeOperands(ByteCode byteCode, - OperandManager operandManager) { + OperandManager operandManager, int codeLength) { // multianewarray has a class ref and a dimension. // The superclass handles the class ref. - super.setByteCodeOperands(byteCode, operandManager); + super.setByteCodeOperands(byteCode, operandManager, codeLength); // We have to handle the dimension. int dimension = operandManager.nextByte(); Index: main/java/org/apache/harmony/pack200/bytecode/forms/TableSwitchForm.java =================================================================== --- main/java/org/apache/harmony/pack200/bytecode/forms/TableSwitchForm.java (revision 0) +++ main/java/org/apache/harmony/pack200/bytecode/forms/TableSwitchForm.java (revision 0) @@ -0,0 +1,94 @@ +package org.apache.harmony.pack200.bytecode.forms; + +import org.apache.harmony.pack200.bytecode.ByteCode; +import org.apache.harmony.pack200.bytecode.OperandManager; + +public class TableSwitchForm extends SwitchForm { + + public TableSwitchForm(int opcode, String name) { + super(opcode, name); + } + + public TableSwitchForm(int opcode, String name, int[] rewrite) { + super(opcode, name, rewrite); + } + + + public void setByteCodeOperands(ByteCode byteCode, + OperandManager operandManager, int codeLength) { + if(switchCaseCountingBroken) return; + int case_count = operandManager.nextCaseCount(); + int default_pc = operandManager.nextLabel(); + int case_values[] = operandManager.nextCaseValues(); + int case_pcs[] = new int[case_count]; + for(int index=0; index < case_count; index++) { + case_pcs[index] = operandManager.nextLabel(); + } + int lowValue = case_values[0]; + int highValue = lowValue + case_count - 1; + // All this gets dumped into the rewrite bytes of the + // poor bytecode. + + int[] labelsArray = new int[case_count + 1]; + labelsArray[0] = default_pc; + for(int index=1; index < case_count + 1; index++) { + labelsArray[index] = case_pcs[index-1]; + } + byteCode.setByteCodeTargets(labelsArray); + + // Unlike most byte codes, the TableSwitch is a + // variable-sized bytecode. Because of this, the + // rewrite array has to be defined here individually + // for each bytecode, rather than in the ByteCodeForm + // class. + + // First, there's the bytecode. Then there are 0-3 + // bytes of padding so that the first (default) + // label is on a 4-byte offset. + int padLength = 3 - (codeLength % 4); + int rewriteSize = 1 + padLength + 4 // defaultbytes + + 4 // lowbyte + + 4 // highbyte + + (4 * case_pcs.length); + + int[] newRewrite = new int[rewriteSize]; + int rewriteIndex = 0; + + // Fill in what we can now + // opcode + newRewrite[rewriteIndex++] = byteCode.getOpcode(); + + // padding + for(int index=0; index < padLength; index++) { + newRewrite[rewriteIndex++] = 0; + } + + // defaultbyte + // This gets overwritten by fixUpByteCodeTargets + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + + // lowbyte + int lowbyteIndex = rewriteIndex; + setRewrite4Bytes(lowValue, lowbyteIndex, newRewrite); + rewriteIndex += 4; + + // highbyte + int highbyteIndex = rewriteIndex; + setRewrite4Bytes(highValue, highbyteIndex, newRewrite); + rewriteIndex += 4; + + // jump offsets + // The case_pcs will get overwritten by fixUpByteCodeTargets + for(int index = 0; index < case_count; index++) { + // offset + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + newRewrite[rewriteIndex++] = -1; + } + byteCode.setRewrite(newRewrite); + } +} Index: main/java/org/apache/harmony/pack200/BcBands.java =================================================================== --- main/java/org/apache/harmony/pack200/BcBands.java (revision 603105) +++ main/java/org/apache/harmony/pack200/BcBands.java (working copy) @@ -299,7 +299,15 @@ // other bytecode bands debug("Parsed *bc_codes (" + bcParsed + ")"); bcCaseCount = decodeBandInt("bc_case_count", in, Codec.UNSIGNED5, bcCaseCountCount); - bcCaseValue = decodeBandInt("bc_case_value", in, Codec.DELTA5, bcCaseCount); + // TODO HACK HACK: Not sure how this should be done. + // bcCaseValue = decodeBandInt("bc_case_value", in, Codec.DELTA5, new int[]{1} /* to test tableswitch */); + bcCaseValue = decodeBandInt("bc_case_value", in, Codec.DELTA5, bcCaseCount /* to test lookupswitch */); + // Every case value needs a label. We weren't able to count these + // above, because we didn't know how many cases there were. + // Have to correct it now. + for(int index=0; index < bcCaseCountCount; index++) { + bcLabelCount += bcCaseCount[index]; + } bcByte = decodeBandInt("bc_byte", in, Codec.BYTE1, bcByteCount); bcShort = decodeBandInt("bc_short", in, Codec.DELTA5, bcShortCount); bcLocal = decodeBandInt("bc_local", in, Codec.UNSIGNED5, bcLocalCount); @@ -337,10 +345,10 @@ bcEscSize = decodeBandInt("bc_escsize", in, Codec.UNSIGNED5, bcEscCount); bcEscByte = decodeBandInt("bc_escbyte", in, Codec.BYTE1, bcEscSize); - OperandManager operandManager = new OperandManager(bcByte, bcShort, - bcLocal, bcLabel, bcIntRef, bcFloatRef, bcLongRef, bcDoubleRef, - bcStringRef, bcClassRef, bcFieldRef, bcMethodRef, bcIMethodRef, - bcThisField, bcSuperField, bcThisMethod, bcSuperMethod, + OperandManager operandManager = new OperandManager(bcCaseCount, bcCaseValue, + bcByte, bcShort, bcLocal, bcLabel, bcIntRef, bcFloatRef, bcLongRef, + bcDoubleRef, bcStringRef, bcClassRef, bcFieldRef, bcMethodRef, + bcIMethodRef, bcThisField, bcSuperField, bcThisMethod, bcSuperMethod, bcInitRef); operandManager.setSegment(segment); @@ -373,7 +381,9 @@ // broken because these tables don't get renumbered // properly. Commenting out the add so the class files // will verify. - //attr.attributes.add(currentAttribute); + // if(currentAttribute.getClass() == LineNumberTableAttribute.class) { + attr.attributes.add(currentAttribute); + // } // Fix up the line numbers if needed if(currentAttribute.hasBCIRenumbering()) { ((BCIRenumberedAttribute)currentAttribute).renumber(attr.byteCodeOffsets);