Index: src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java (revision 576831) +++ src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java (working copy) @@ -24,7 +24,7 @@ * */ public class AttrDefinitionBands extends BandSet { - + private int[] attributeDefinitionHeader; private String[] attributeDefinitionLayout; Index: src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java =================================================================== --- src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java (revision 576831) +++ src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java (working copy) @@ -209,7 +209,7 @@ } public void add(AttributeLayout layout) { - layouts[layout.getContext()].put(Integer.valueOf(layout.getIndex()), layout); + layouts[layout.getContext()].put(new Integer(layout.getIndex()), layout); } public AttributeLayout getAttributeLayout(String name, int context) Index: src/main/java/org/apache/harmony/pack200/BandSet.java =================================================================== --- src/main/java/org/apache/harmony/pack200/BandSet.java (revision 576831) +++ src/main/java/org/apache/harmony/pack200/BandSet.java (working copy) @@ -71,6 +71,24 @@ return result; } + public int[][] decodeBandInt(String name, InputStream in, BHSDCodec defaultCodec, int[] counts) throws IOException, Pack200Exception { + int[][] result = new int[counts.length][]; + int totalCount = 0; + for (int i = 0; i < counts.length; i++) { + totalCount += counts[i]; + } + int[] twoDResult = decodeBandInt(name, in, defaultCodec, totalCount); + int index = 0; + for (int i = 0; i < result.length; i++) { + result[i] = new int[counts[i]]; + for(int j = 0; j < result[i].length; j++) { + result[i][j] = twoDResult[index]; + index++; + } + } + return result; + } + /** * Decode a band and return an array of long[] values * @@ -184,7 +202,7 @@ public String[] parseReferences(String name, InputStream in, BHSDCodec codec, int count, String[] reference) throws IOException, Pack200Exception { - return parseReferences(name, in, codec, 1, new int[] { count }, + return parseReferences(name, in, codec, new int[] { count }, reference)[0]; } @@ -214,9 +232,10 @@ * if a problem occurs with an unexpected value or unsupported * codec */ - protected String[][] parseReferences(String name, InputStream in, - BHSDCodec codec, int count, int counts[], String[] reference) + public String[][] parseReferences(String name, InputStream in, + BHSDCodec codec, int counts[], String[] reference) throws IOException, Pack200Exception { + int count = counts.length; if (count == 0) { return new String[][] { {} }; } Index: src/main/java/org/apache/harmony/pack200/BcBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/BcBands.java (revision 572724) +++ src/main/java/org/apache/harmony/pack200/BcBands.java (working copy) @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Arrays; import org.apache.harmony.pack200.bytecode.ByteCode; import org.apache.harmony.pack200.bytecode.CodeAttribute; @@ -26,11 +27,36 @@ import org.apache.harmony.pack200.bytecode.CodeAttribute; /** - * + * Pack200 Bytecode bands */ public class BcBands extends BandSet { + // the bytecodes for each method in each class as they come (i.e. in their packed format) private byte[][][] methodByteCodePacked; + private int[] bcCaseCount; + private int[][] bcCaseValue; + private int[] bcByte; + private int[] bcLocal; + private int[] bcShort; + private int[] bcLabel; + private int[] bcIntRef; + private int[] bcFloatRef; + private int[] bcLongRef; + private int[] bcDoubleRef; + private int[] bcStringRef; + private int[] bcClassRef; + private int[] bcFieldRef; + private int[] bcMethodRef; + private int[] bcIMethodRef; + private int[] bcThisField; + private int[] bcSuperField; + private int[] bcThisMethod; + private int[] bcSuperMethod; + private int[] bcInitRef; + private int[] bcEscRef; + private int[] bcEscRefSize; + private int[] bcEscSize; + private int[][] bcEscByte; /** * @param header @@ -61,12 +87,27 @@ ArrayList[][] methodAttributes = segment.getClassBands().getMethodAttributes(); String[][] methodDescr = segment.getClassBands().getMethodDescr(); + int bcCaseCountCount = 0; + int bcByteCount = 0; + int bcShortCount = 0; + int bcLocalCount = 0; + int bcLabelCount = 0; + int bcIntRefCount = 0; + int bcFloatRefCount = 0; + int bcLongRefCount = 0; + int bcDoubleRefCount = 0; int bcStringRefCount = 0; - int bcInitRefCount = 0; + int bcClassRefCount = 0; int bcFieldRefCount = 0; - int bcThisFieldCount = 0; int bcMethodRefCount = 0; int bcIMethodRefCount = 0; + int bcThisFieldCount = 0; + int bcSuperFieldCount = 0; + int bcThisMethodCount = 0; + int bcSuperMethodCount = 0; + int bcInitRefCount = 0; + int bcEscCount = 0; + int bcEscRefCount = 0; AttributeLayout abstractModifier = attributeDefinitionMap .getAttributeLayout(AttributeLayout.ACC_ABSTRACT, @@ -92,6 +133,11 @@ codeBytes.write(code); methodByteCodePacked[c][m] = codeBytes.toByteArray(); bcParsed += methodByteCodePacked[c][m].length; + int[] codes = new int[methodByteCodePacked[c][m].length]; + for (int i = 0; i < codes.length; i++) { + codes[i] = methodByteCodePacked[c][m][i] & 0xff; + } + debug(Arrays.toString(codes)); for (int i = 0; i < methodByteCodePacked[c][m].length; i++) { int codePacked = 0xff & methodByteCodePacked[c][m][i]; // TODO a lot of this needs to be encapsulated in the @@ -103,9 +149,56 @@ // once they've been gotten. But that's for another // time. switch (codePacked) { + case 16: // bipush + case 188: // newarray + bcByteCount++; + break; + case 17: // sipush + bcShortCount++; + break; case 18: // (a)ldc + case 19: // aldc_w bcStringRefCount++; break; + case 234: // ildc + case 237: // ildc_w + bcIntRefCount++; + break; + case 235: // fldc + case 238: // fldc_w + bcFloatRefCount++; + break; + case 197: // multianewarray + bcByteCount++; + // fallthrough intended + case 233: // cldc + case 236: // cldc_w + case 187: // new + case 189: // anewarray + case 192: // checkcast + case 193: // instanceof + bcClassRefCount++; + break; + case 20: // lldc2_w + bcLongRefCount++; + break; + case 239: // dldc2_w + bcDoubleRefCount++; + break; + case 169: // ret + bcLocalCount++; + break; + case 167: // goto + case 168: // jsr + case 200: // goto_w + case 201: // jsr_w + bcLabelCount++; + break; + case 170: // tableswitch + case 171: // lookupswitch + bcCaseCountCount++; + bcLabelCount++; + break; case 178: // getstatic case 179: // putstatic case 180: // getfield @@ -124,15 +217,75 @@ case 203: // putstatic_this case 204: // getfield_this case 205: // putfield_this + case 209: // aload_0_getstatic_this + case 210: // aload_0_putstatic_this + case 211: // aload_0_putfield_this + case 212: // aload_0_putfield_this bcThisFieldCount++; break; - case 231: // invoke_special_init + case 206: // invokevirtual_this + case 207: // invokespecial_this + case 208: // invokestatic_this + case 213: // aload_0_invokevirtual_this + case 214: // aload_0_invokespecial_this + case 215: // aload_0_invokestatic_this + bcThisMethodCount++; + break; + case 216: // getstatic_super + case 217: // putstatic_super + case 218: // getfield_super + case 219: // putfield_super + case 223: // aload_0_getstatic_super + case 224: // aload_0_putstatic_super + case 225: // aload_0_getfield_super + case 226: // aload_0_putfield_super + bcSuperFieldCount++; + break; + case 220: // invokevirtual_super + case 221: // invokespecial_super + case 222: // invokestatic_super + case 227: // aload_0_invokevirtual_super + case 228: // aload_0_invokespecial_super + case 229: // aload_0_invokestatic_super + bcSuperMethodCount++; + break; + case 132: // iinc + bcLocalCount++; + bcByteCount++; + break; + case 196: // wide + int nextInstruction = 0xff & methodByteCodePacked[c][m][i+1]; + if (nextInstruction == 132) { // iinc + bcLocalCount += 2; + bcShortCount++; + } else if (endsWithLoad(nextInstruction) + || endsWithStore(nextInstruction) + || nextInstruction == 169) { + bcLocalCount += 2; + } else { + debug("Found unhandled " + ByteCode.getByteCode(nextInstruction)); + } + i++; + break; + case 230: // invokespecial_this_init + case 231: // invokespecial_super_init + case 232: // invokespecial_new_init bcInitRefCount++; break; - + case 253: // ref_escape + bcEscRefCount++; + break; + case 254: // byte_escape + bcEscCount++; + break; default: // unhandled specifically at this stage - debug("Found unhandled " - + ByteCode.getByteCode(codePacked)); + if(endsWithLoad(codePacked) || endsWithStore(codePacked)) { + bcLocalCount++; + } else if (startsWithIf(codePacked)) { + bcLabelCount++; + } else { + debug("Found unhandled " + ByteCode.getByteCode(codePacked)); + } } } } @@ -138,41 +291,49 @@ } } } - // other bytecode bands - debug("Parsed *bc_codes (" + bcParsed + ")"); - debug("unimplemented bc_case_count"); - debug("unimplemented bc_case_value"); - debug("unimplemented bc_byte"); - debug("unimplemented bc_short"); - debug("unimplemented bc_local"); - debug("unimplemented bc_label"); - debug("unimplemented bc_intref"); - debug("unimplemented bc_floatref"); - debug("unimplemented bc_longref"); - debug("unimplemented bc_doubleref"); - int[] bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5, - bcStringRefCount); - debug("unimplemented bc_classref"); - int[] bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5, - bcFieldRefCount); - int[] bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5, - bcMethodRefCount); - int[] bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5, - bcIMethodRefCount); - int[] bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5, - bcThisFieldCount); - debug("unimplemented bc_superfield"); - debug("unimplemented bc_thismethod"); - debug("unimplemented bc_supermethod"); - debug("unimplemented bc_initref"); - int[] bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5, - bcInitRefCount); - debug("unimplemented bc_escref"); - debug("unimplemented bc_escrefsize"); - debug("unimplemented bc_escsize"); - debug("unimplemented bc_escbyte"); - int i = 0; - for (int c = 0; c < classCount; c++) { + // 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); + bcByte = decodeBandInt("bc_byte", in, Codec.BYTE1, bcByteCount); + bcShort = decodeBandInt("bc_short", in, Codec.DELTA5, bcShortCount); + bcLocal = decodeBandInt("bc_local", in, Codec.UNSIGNED5, bcLocalCount); + bcLabel = decodeBandInt("bc_label", in, Codec.BRANCH5, bcLabelCount); + bcIntRef = decodeBandInt("bc_intref", in, Codec.DELTA5, bcIntRefCount); + bcFloatRef = decodeBandInt("bc_floatref", in, Codec.DELTA5, + bcFloatRefCount); + bcLongRef = decodeBandInt("bc_longref", in, Codec.DELTA5, + bcLongRefCount); + bcDoubleRef = decodeBandInt("bc_doubleref", in, Codec.DELTA5, + bcDoubleRefCount); + bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5, + bcStringRefCount); + bcClassRef = decodeBandInt("bc_classref", in, Codec.UNSIGNED5, + bcClassRefCount); + bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5, + bcFieldRefCount); + bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5, + bcMethodRefCount); + bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5, + bcIMethodRefCount); + bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5, + bcThisFieldCount); + bcSuperField = decodeBandInt("bc_superfield", in, Codec.UNSIGNED5, + bcSuperFieldCount); + bcThisMethod = decodeBandInt("bc_thismethod", in, Codec.UNSIGNED5, + bcThisMethodCount); + bcSuperMethod = decodeBandInt("bc_supermethod", in, Codec.UNSIGNED5, + bcSuperMethodCount); + bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5, + bcInitRefCount); + bcEscRef = decodeBandInt("bc_escref", in, Codec.UNSIGNED5, + bcEscRefCount); + bcEscRefSize = decodeBandInt("bc_escrefsize", in, Codec.UNSIGNED5, bcEscRefCount); + bcEscSize = decodeBandInt("bc_escsize", in, Codec.UNSIGNED5, bcEscCount); + bcEscByte = decodeBandInt("bc_escbyte", in, Codec.BYTE1, bcEscSize); + + int i = 0; + for (int c = 0; c < classCount; c++) { int numberOfMethods = methodFlags[c].length; for (int m = 0; m < numberOfMethods; m++) { long methodFlag = methodFlags[c][m]; @@ -192,7 +353,120 @@ } } } + } + + private boolean startsWithIf(int codePacked) { + return (codePacked >= 153 && codePacked <= 166) + || (codePacked == 198) + || (codePacked == 199); + } + + private boolean endsWithLoad(int codePacked) { + return (codePacked >= 21 && codePacked <= 25); + } + + private boolean endsWithStore(int codePacked) { + return (codePacked >= 54 && codePacked <= 58); + } + + public byte[][][] getMethodByteCodePacked() { + return methodByteCodePacked; + } + + public int[] getBcCaseCount() { + return bcCaseCount; + } + public int[][] getBcCaseValue() { + return bcCaseValue; } + public int[] getBcByte() { + return bcByte; + } + + public int[] getBcClassRef() { + return bcClassRef; + } + + public int[] getBcDoubleRef() { + return bcDoubleRef; + } + + public int[] getBcFieldRef() { + return bcFieldRef; + } + + public int[] getBcFloatRef() { + return bcFloatRef; + } + + public int[] getBcIMethodRef() { + return bcIMethodRef; + } + + public int[] getBcInitRef() { + return bcInitRef; + } + + public int[] getBcIntRef() { + return bcIntRef; + } + + public int[] getBcLabel() { + return bcLabel; + } + + public int[] getBcLocal() { + return bcLocal; + } + + public int[] getBcLongRef() { + return bcLongRef; + } + + public int[] getBcMethodRef() { + return bcMethodRef; + } + + public int[] getBcShort() { + return bcShort; + } + + public int[] getBcStringRef() { + return bcStringRef; + } + + public int[] getBcSuperField() { + return bcSuperField; + } + + public int[] getBcSuperMethod() { + return bcSuperMethod; + } + + public int[] getBcThisField() { + return bcThisField; + } + + public int[] getBcThisMethod() { + return bcThisMethod; + } + + public int[] getBcEscRef() { + return bcEscRef; + } + + public int[] getBcEscRefSize() { + return bcEscRefSize; + } + + public int[] getBcEscSize() { + return bcEscSize; + } + + public int[][] getBcEscByte() { + return bcEscByte; + } + } Index: src/main/java/org/apache/harmony/pack200/ClassBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/ClassBands.java (revision 572724) +++ src/main/java/org/apache/harmony/pack200/ClassBands.java (working copy) @@ -20,6 +20,8 @@ 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.bytecode.CPClass; import org.apache.harmony.pack200.bytecode.ConstantValueAttribute; @@ -26,7 +28,7 @@ import org.apache.harmony.pack200.bytecode.ExceptionsAttribute; /** - * + * */ public class ClassBands extends BandSet { @@ -41,7 +43,7 @@ private int[] classMethodCount; private String[] classSuper; - + private String[] classThis; private int[] codeHandlerCount; @@ -57,11 +59,11 @@ private String[][] fieldDescr; private long[][] fieldFlags; - + private int methodAttrCount; private ArrayList[][] methodAttributes; - + private String[][] methodDescr; private ExceptionsAttribute[][] methodExceptions; @@ -71,13 +73,16 @@ private AttributeLayoutMap attrMap; private CpBands cpBands; - + + private int codeAttrCount; + /** * @param header */ - public ClassBands(Segment segment){ + public ClassBands(Segment segment) { super(segment); - this.attrMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap(); + this.attrMap = segment.getAttrDefinitionBands() + .getAttributeDefinitionMap(); this.cpBands = segment.getCpBands(); } @@ -96,8 +101,7 @@ * * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream) */ - public void unpack(InputStream in) throws IOException, - Pack200Exception { + public void unpack(InputStream in) throws IOException, Pack200Exception { int classCount = header.getClassCount(); classThis = parseReferences("class_this", in, Codec.DELTA5, classCount, cpBands.getCpClass()); @@ -108,7 +112,7 @@ in, Codec.DELTA5, classCount); // for (int i = 0; i < classCount; i++) { classInterfaces = parseReferences("class_interface", in, Codec.DELTA5, - classCount, classInterfaceLengths, cpBands.getCpClass()); + classInterfaceLengths, cpBands.getCpClass()); // } classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount); @@ -126,7 +130,7 @@ int classCount = header.getClassCount(); SegmentOptions options = header.getOptions(); fieldDescr = parseReferences("field_descr", in, Codec.DELTA5, - classCount, classFieldCount, cpBands.getCpDescriptor()); + classFieldCount, cpBands.getCpDescriptor()); fieldFlags = parseFlags("field_flags", in, classCount, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi()); for (int i = 0; i < classCount; i++) { @@ -141,8 +145,8 @@ "There are attribute flags, and I don't know what to do with them"); debug("unimplemented field_attr_indexes"); debug("unimplemented field_attr_calls"); - AttributeLayout layout = attrMap.getAttributeLayout( - "ConstantValue", AttributeLayout.CONTEXT_FIELD); + AttributeLayout layout = attrMap.getAttributeLayout("ConstantValue", + AttributeLayout.CONTEXT_FIELD); Codec codec = layout.getCodec(); fieldAttributes = new ArrayList[classCount][]; for (int i = 0; i < classCount; i++) { @@ -161,7 +165,8 @@ // be e.g. KIB or KIH if (type.equals("B") || type.equals("H")) type = "I"; - Object value = layout.getValue(result, type, cpBands.getConstantPool()); + Object value = layout.getValue(result, type, cpBands + .getConstantPool()); fieldAttributes[i][j] .add(new ConstantValueAttribute(value)); debug("Processed value " + value + " for ConstantValue"); @@ -168,8 +173,37 @@ } } } - debug("unimplemented field_Signature_RS"); - parseMetadataBands(AttributeLayout.CONTEXT_FIELD); + + layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, + AttributeLayout.CONTEXT_FIELD); + codec = layout.getCodec(); +// fieldAttributes = new ArrayList[classCount][]; + for (int i = 0; i < classCount; i++) { +// fieldAttributes[i] = new ArrayList[fieldFlags[i].length]; + for (int j = 0; j < fieldFlags[i].length; j++) { +// fieldAttributes[i][j] = new ArrayList(); + long flag = fieldFlags[i][j]; + if (layout.matches(flag)) { + // we've got a value to read + long result = codec.decode(in); +// String desc = fieldDescr[i][j]; +// int colon = desc.indexOf(':'); +// // String name = desc.substring(0, colon); +// String type = desc.substring(colon + 1); +// // TODO Got to get better at this ... in any case, it should +// // be e.g. KIB or KIH +// if (type.equals("B") || type.equals("H")) +// type = "I"; +// Object value = layout.getValue(result, type, cpBands +// .getConstantPool()); +// fieldAttributes[i][j] +// .add(new ConstantValueAttribute(value)); + debug("Found a signature attribute: " + result); + } + } + } +// debug("unimplemented field_Signature_RS"); + parseFieldMetadataBands(); } private void parseMethodBands(InputStream in) throws IOException, @@ -177,7 +211,7 @@ int classCount = header.getClassCount(); SegmentOptions options = header.getOptions(); methodDescr = parseReferences("method_descr", in, Codec.MDELTA5, - classCount, classMethodCount, cpBands.getCpDescriptor()); + classMethodCount, cpBands.getCpDescriptor()); methodFlags = parseFlags("method_flags", in, classCount, classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi()); for (int i = 0; i < classCount; i++) { @@ -203,9 +237,9 @@ } parseAttributeMethodExceptions(in); parseAttributeMethodSignature(in); - parseMetadataBands(AttributeLayout.CONTEXT_METHOD); + parseMethodMetadataBands(); } - + /** * @param in * @throws Pack200Exception @@ -215,8 +249,8 @@ throws Pack200Exception, IOException { // TODO Should refactor this stuff into the layout somehow int classCount = header.getClassCount(); - AttributeLayout layout = attrMap.getAttributeLayout( - "Exceptions", AttributeLayout.CONTEXT_METHOD); + AttributeLayout layout = attrMap.getAttributeLayout("Exceptions", + AttributeLayout.CONTEXT_METHOD); Codec codec = layout.getCodec(); methodExceptions = new ExceptionsAttribute[classCount][]; int[][] numExceptions = new int[classCount][]; @@ -235,20 +269,20 @@ long flag = methodFlags[i][j]; int n = numExceptions[i][j]; if (n > 0) { - CPClass[] exceptions = new CPClass[n]; - if (layout.matches(flag)) { - for (int k = 0; k < n; k++) { - long result = codec.decode(in); - exceptions[k] = new CPClass(cpBands.getCpClass()[(int) result]); - } - } - methodExceptions[i][j] = new ExceptionsAttribute(exceptions); - methodAttributes[i][j].add(methodExceptions[i][j]); - } + CPClass[] exceptions = new CPClass[n]; + if (layout.matches(flag)) { + for (int k = 0; k < n; k++) { + long result = codec.decode(in); + exceptions[k] = new CPClass( + cpBands.getCpClass()[(int) result]); + } + } + methodExceptions[i][j] = new ExceptionsAttribute(exceptions); + methodAttributes[i][j].add(methodExceptions[i][j]); + } } } } - /** * @param name @@ -258,12 +292,11 @@ private void parseAttributeUnknown(String name, int context, long[][] flags) throws Pack200Exception { debug("Parsing unknown attributes for " + name); - AttributeLayout layout = attrMap.getAttributeLayout( - name, context); - int count = SegmentUtils.countMatches(flags, layout); - if (count > 0) - throw new Error("We've got data for " + name - + " and we don't know what to do with it (yet)"); + AttributeLayout layout = attrMap.getAttributeLayout(name, context); + int count = SegmentUtils.countMatches(flags, layout); + if (count > 0) + throw new Error("We've got data for " + name + + " and we don't know what to do with it (yet)"); } /** @@ -294,8 +327,8 @@ debug("unimplemented class_attr_indexes"); debug("unimplemented class_attr_calls"); AttributeLayout layout = attrMap.getAttributeLayout( - AttributeLayout.ATTRIBUTE_SOURCE_FILE, - AttributeLayout.CONTEXT_CLASS); + AttributeLayout.ATTRIBUTE_SOURCE_FILE, + AttributeLayout.CONTEXT_CLASS); for (int i = 0; i < classCount; i++) { long flag = classFlags[i]; if (layout.matches(flag)) { @@ -303,7 +336,8 @@ // TODO File this as a sourcefile attribute and don't generate // everything below long result = layout.getCodec().decode(in); - Object value = layout.getValue(result, cpBands.getConstantPool()); + Object value = layout.getValue(result, cpBands + .getConstantPool()); debug("Processed value " + value + " for SourceFile"); } } @@ -310,7 +344,7 @@ debug("unimplemented class_EnclosingMethod_RC"); debug("unimplemented class_EnclosingMethod_RDN"); debug("unimplemented class_Signature_RS"); - parseMetadataBands(AttributeLayout.CONTEXT_CLASS); + parseClassMetadataBands(); debug("unimplemented class_InnerClasses_N"); debug("unimplemented class_InnerClasses_RC"); debug("unimplemented class_InnerClasses_F"); @@ -319,7 +353,6 @@ debug("unimplemented class_file_version_minor_H"); debug("unimplemented class_file_version_major_H"); } - private void parseCodeBands(InputStream in) throws Pack200Exception, IOException { @@ -370,49 +403,122 @@ throw new IllegalStateException("Shouldn't get here either"); } } - debug("unimplemented code_headers"); - debug("unimplemented code_max_stack"); - debug("unimplemented code_max_na_locals"); - debug("unimplemented code_hander_count"); - debug("unimplemented code_hander_start_P"); - debug("unimplemented code_hander_end_PO"); - debug("unimplemented code_hander_catch_PO"); - debug("unimplemented code_hander_class_RC"); - parseCodeAttrBands(in); + int codeFlagsCount = segment.getSegmentHeader().getOptions().hasAllCodeFlags() ? + codeBands : codeSpecialHeader; + parseCodeAttrBands(in, codeFlagsCount); } - - private void parseCodeAttrBands(InputStream in) { - debug("unimplemented code_flags"); + private void parseCodeAttrBands(InputStream in, int codeFlagsCount) throws IOException, Pack200Exception { + long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5, segment.getSegmentHeader().getOptions().hasCodeFlagsHi()); + for (int i = 0; i < codeFlagsCount; i++) { + long flag = codeFlags[i]; + if ((flag & (1 << 16)) != 0) + codeAttrCount++; + } + if (codeAttrCount > 0) + throw new Error( + "There are attribute flags, and I don't know what to do with them"); debug("unimplemented code_attr_count"); debug("unimplemented code_attr_indexes"); debug("unimplemented code_attr_calls"); - debug("unimplemented code_LineNumberTable_N"); - debug("unimplemented code_LineNumberTable_bci_P"); - debug("unimplemented code_LineNumberTable_line"); - String[] types = { "LocalVariableTable", "LocalVariableTypeTable" }; + + int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE)); + int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5, lineNumberTableCount); + int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5, lineNumberTableN); + int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5, lineNumberTableN); + String[] types = { AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE, AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE }; for (int i = 0; i < types.length; i++) { String type = types[i]; - debug("unimplemented code_" + type + "_N"); - debug("unimplemented code_" + type + "_bci_P"); - debug("unimplemented code_" + type + "_span_O"); - debug("unimplemented code_" + type + "_name_RU"); - debug("unimplemented code_" + type + "_type_RS"); - debug("unimplemented code_" + type + "_slot"); + int lengthNBand = SegmentUtils.countMatches(codeFlags, attrMap.getAttributeLayout(type, AttributeLayout.CONTEXT_CODE)); + int[] nBand = decodeBandInt("code_" + type + "_N", in, Codec.UNSIGNED5, lengthNBand); + int[][] bciP = decodeBandInt("code_" + type + "_bci_P", in, Codec.BCI5, nBand); + int[][] spanO = decodeBandInt("code_" + type + "_span_O", in, Codec.BRANCH5, nBand); + String[][] nameRU = parseReferences("code_" + type + "_name_RU", in, Codec.UNSIGNED5, nBand, cpBands.getCpUTF8()); + String[][] typeRS = parseReferences("code_" + type + "_type_RS", in, Codec.UNSIGNED5, nBand, cpBands.getCpSignature()); + int[][] slot = decodeBandInt("code_" + type + "_slot", in, Codec.UNSIGNED5, nBand); + } + } + + + + private void parseFieldMetadataBands() throws Pack200Exception { + String[] RxA = new String[] { "RVA", "RIA" }; + + AttributeLayout rvaLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, + AttributeLayout.CONTEXT_FIELD); + AttributeLayout riaLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, + AttributeLayout.CONTEXT_FIELD); + + int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout); + int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout); + if (rvaCount > 0 || riaCount > 0) { + throw new Error("Field metadata not handled"); + } + + // AttributeLayout layout = + // map.get(RuntimeVisibleAnnotations,class/field/method as int) + // foreachheader ... + // if layout.matches(header[n] or whatever) + String contextName = "field"; + for (int i = 0; i < RxA.length; i++) { + String rxa = RxA[i]; + if (rxa.indexOf("P") >= 0) { + debug("unimplemented " + contextName + "_" + rxa + "_param_NB"); + } + if (!rxa.equals("AD")) { + debug("unimplemented " + contextName + "_" + rxa + "_anno_N"); + debug("unimplemented " + contextName + "_" + rxa + "_type_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_pair_N"); + debug("unimplemented " + contextName + "_" + rxa + "_name_RU"); + } + debug("unimplemented " + contextName + "_" + rxa + "_T"); + debug("unimplemented " + contextName + "_" + rxa + "_caseI_KI"); + debug("unimplemented " + contextName + "_" + rxa + "_caseD_KD"); + debug("unimplemented " + contextName + "_" + rxa + "_caseF_KF"); + debug("unimplemented " + contextName + "_" + rxa + "_caseJ_KJ"); + debug("unimplemented " + contextName + "_" + rxa + "_casec_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_caseet_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_caseec_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_cases_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_casearray_N"); + debug("unimplemented " + contextName + "_" + rxa + "_nesttype_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_nestpair_N"); + debug("unimplemented " + contextName + "_" + rxa + "_nestname_RU"); } } - private void parseMetadataBands(int context) throws Pack200Exception { - String[] RxA; - if (AttributeLayout.CONTEXT_METHOD == context) { - RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" }; - } else if (AttributeLayout.CONTEXT_FIELD == context - || AttributeLayout.CONTEXT_CLASS == context) { - RxA = new String[] { "RVA", "RIA" }; - } else { - throw new Pack200Exception("Unknown type of metadata unit " - + context); + private void parseMethodMetadataBands() throws Pack200Exception { + String[] RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" }; + int[] rxaCounts = new int[] { 0, 0, 0, 0, 0 }; + AttributeLayout rvaLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, + AttributeLayout.CONTEXT_METHOD); + AttributeLayout riaLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, + AttributeLayout.CONTEXT_METHOD); + AttributeLayout rvpaLayout = attrMap + .getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, + AttributeLayout.CONTEXT_METHOD); + AttributeLayout ripaLayout = attrMap + .getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, + AttributeLayout.CONTEXT_METHOD); + AttributeLayout adLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, + AttributeLayout.CONTEXT_METHOD); + AttributeLayout[] rxaLayouts = new AttributeLayout[] { rvaLayout, + riaLayout, rvpaLayout, ripaLayout, adLayout }; + + for (int i = 0; i < rxaLayouts.length; i++) { + rxaCounts[i] = SegmentUtils.countMatches(methodFlags, rxaLayouts[i]); + if (rxaCounts[i] > 0) { + throw new Error("Found method metadata"); + } } + // AttributeLayout layout = // map.get(RuntimeVisibleAnnotations,class/field/method as int) // foreachheader ... @@ -417,10 +523,7 @@ // map.get(RuntimeVisibleAnnotations,class/field/method as int) // foreachheader ... // if layout.matches(header[n] or whatever) - String contextName = (AttributeLayout.CONTEXT_METHOD == context ? "method" - : (AttributeLayout.CONTEXT_FIELD == context ? "field" - : (AttributeLayout.CONTEXT_CLASS == context ? "class" - : "unkowon"))); + String contextName = "method"; for (int i = 0; i < RxA.length; i++) { String rxa = RxA[i]; if (rxa.indexOf("P") >= 0) { @@ -448,6 +551,52 @@ } } + private void parseClassMetadataBands() throws Pack200Exception { + String[] RxA = new String[] { "RVA", "RIA" }; + + AttributeLayout rvaLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, + AttributeLayout.CONTEXT_CLASS); + AttributeLayout riaLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, + AttributeLayout.CONTEXT_CLASS); + int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout); + int riaCount = SegmentUtils.countMatches(classFlags, riaLayout); + if (rvaCount > 0 || riaCount > 0) { + throw new Error("Class metadata not handled"); + } + // AttributeLayout layout = + // map.get(RuntimeVisibleAnnotations,class/field/method as int) + // foreachheader ... + // if layout.matches(header[n] or whatever) + String contextName = "class"; + for (int i = 0; i < RxA.length; i++) { + String rxa = RxA[i]; + if (rxa.indexOf("P") >= 0) { + debug("unimplemented " + contextName + "_" + rxa + "_param_NB"); + } + if (!rxa.equals("AD")) { + debug("unimplemented " + contextName + "_" + rxa + "_anno_N"); + debug("unimplemented " + contextName + "_" + rxa + "_type_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_pair_N"); + debug("unimplemented " + contextName + "_" + rxa + "_name_RU"); + } + debug("unimplemented " + contextName + "_" + rxa + "_T"); + debug("unimplemented " + contextName + "_" + rxa + "_caseI_KI"); + debug("unimplemented " + contextName + "_" + rxa + "_caseD_KD"); + debug("unimplemented " + contextName + "_" + rxa + "_caseF_KF"); + debug("unimplemented " + contextName + "_" + rxa + "_caseJ_KJ"); + debug("unimplemented " + contextName + "_" + rxa + "_casec_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_caseet_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_caseec_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_cases_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_casearray_N"); + debug("unimplemented " + contextName + "_" + rxa + "_nesttype_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_nestpair_N"); + debug("unimplemented " + contextName + "_" + rxa + "_nestname_RU"); + } + } + public int getClassAttrCount() { return classAttrCount; } Index: src/main/java/org/apache/harmony/pack200/Segment.java =================================================================== --- src/main/java/org/apache/harmony/pack200/Segment.java (revision 572724) +++ src/main/java/org/apache/harmony/pack200/Segment.java (working copy) @@ -357,7 +357,6 @@ return cpBands; } - protected FileBands getFileBands() { return fileBands; } @@ -362,12 +361,6 @@ return fileBands; } - - protected SegmentHeader getHeader() { - return header; - } - - protected IcBands getIcBands() { return icBands; } @@ -372,4 +365,4 @@ return icBands; } -} +} \ No newline at end of file Index: src/main/java/org/apache/harmony/pack200/bytecode/ByteCode.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (revision 572384) +++ src/main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (working copy) @@ -240,11 +240,71 @@ byteCodeArray[203] = new ByteCode(203, "putstatic_this", new int[] { 179, 0, 0 }); byteCodeArray[204] = new ByteCode(204, "getfield_this", new int[] { - 180, 0, 0 }); - byteCodeArray[205] = new ByteCode(205, "putfield_this", new int[] { - 181, 0, 0 }); - byteCodeArray[231] = new ByteCode(231, "invokespecial_super_init", - new int[] { 183, 0, 0 }); + 180, 0, 0 }); + byteCodeArray[205] = new ByteCode(205, "putfield_this", new int[] { + 181, 0, 0 }); + byteCodeArray[206] = new ByteCode(206, "invokevirtual_this", new int[] { + 182, 0, 0 }); + byteCodeArray[207] = new ByteCode(207, "invokespecial_this", new int[] { + 183, 0, 0 }); + byteCodeArray[208] = new ByteCode(208, "invokestatic_this", new int[] { + 184, 0, 0 }); + byteCodeArray[209] = new ByteCode(209, "aload_0_getstatic_this", + new int[] { 42, 178, 0, 0 }); + byteCodeArray[210] = new ByteCode(210, "aload_0_putstatic_this", + new int[] { 42, 179, 0, 0 }); + byteCodeArray[211] = new ByteCode(211, "aload_0_getfield_this", + new int[] { 42, 180, 0, 0 }); + byteCodeArray[212] = new ByteCode(212, "aload_0_putfield_this", + new int[] { 42, 181, 0, 0 }); + byteCodeArray[213] = new ByteCode(213, "aload_0_invokevirtual_this", + new int[] { 42, 182, 0, 0 }); + byteCodeArray[214] = new ByteCode(214, "aload_0_invokespecial_this", + new int[] { 42, 183, 0, 0 }); + byteCodeArray[215] = new ByteCode(215, "aload_0_invokestatic_this", + new int[] { 42, 184, 0, 0 }); + byteCodeArray[216] = new ByteCode(216, "getstatic_super", new int[] { + 178, 0, 0 }); + byteCodeArray[217] = new ByteCode(217, "putstatic_super", new int[] { + 179, 0, 0 }); + byteCodeArray[218] = new ByteCode(218, "getfield_super", new int[] { + 180, 0, 0 }); + byteCodeArray[219] = new ByteCode(219, "putfield_super", new int[] { + 181, 0, 0 }); + byteCodeArray[220] = new ByteCode(220, "invokevirtual_super", + new int[] { 182, 0, 0 }); + byteCodeArray[221] = new ByteCode(221, "invokespecial_super", + new int[] { 183, 0, 0 }); + byteCodeArray[222] = new ByteCode(222, "invokestatic_super", new int[] { + 184, 0, 0 }); + byteCodeArray[223] = new ByteCode(223, "aload_0_getstatic_super", + new int[] { 42, 178, 0, 0 }); + byteCodeArray[224] = new ByteCode(224, "aload_0_putstatic_super", + new int[] { 42, 179, 0, 0 }); + byteCodeArray[225] = new ByteCode(225, "aload_0_getfield_super", + new int[] { 42, 180, 0, 0 }); + byteCodeArray[226] = new ByteCode(226, "aload_0_putfield_super", + new int[] { 42, 181, 0, 0 }); + byteCodeArray[227] = new ByteCode(227, "aload_0_invokevirtual_super", + new int[] { 42, 182, 0, 0 }); + byteCodeArray[228] = new ByteCode(228, "aload_0_invokespecial_super", + new int[] { 42, 183, 0, 0 }); + byteCodeArray[229] = new ByteCode(229, "aload_0_invokestatic_super", + new int[] { 42, 184, 0, 0 }); + byteCodeArray[230] = new ByteCode(230, "invokespecial_this_init", + new int[] { 183, 0, 0 }); + byteCodeArray[231] = new ByteCode(231, "invokespecial_super_init", + new int[] { 183, 0, 0 }); + byteCodeArray[232] = new ByteCode(232, "invokespecial_new_init", + new int[] { 184, 0, 0 }); + byteCodeArray[233] = new ByteCode(233, "cldc", new int[] { 18, 0 }); + byteCodeArray[234] = new ByteCode(234, "ildc", new int[] { 18, 0 }); + byteCodeArray[235] = new ByteCode(235, "fldc", new int[] { 18, 0 }); + byteCodeArray[236] = new ByteCode(236, "cldc_w", new int[] { 19, 0 }); + byteCodeArray[237] = new ByteCode(237, "ildc_w", new int[] { 19, 0 }); + byteCodeArray[238] = new ByteCode(238, "fldc_w", new int[] { 19, 0 }); + byteCodeArray[239] = new ByteCode(239, "dldc2_w", new int[] { 20, 0 }); + // Reserved bytecodes byteCodeArray[254] = new ByteCode(254, "impdep1"); byteCodeArray[255] = new ByteCode(255, "impdep2"); @@ -261,7 +321,7 @@ ByteCode byteCode = (ByteCode) byteCodes .get(new Integer(0xff & opcode)); if (byteCode == null) - throw new Error("Unknown bytecode"); + throw new Error("Unknown bytecode: " + opcode); return byteCode; } Index: src/main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (revision 572384) +++ src/main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java (working copy) @@ -37,7 +37,7 @@ this.maxStack = maxStack; this.codeLength = 0; for (int i = 0; i < codePacked.length; i++) { - ByteCode byteCode = ByteCode.getByteCode(codePacked[i]); + ByteCode byteCode = ByteCode.getByteCode(codePacked[i] & 0xff); byteCodes.add(byteCode); this.codeLength += byteCode.getLength(); } Index: src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java (revision 572724) +++ src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java (working copy) @@ -34,13 +34,9 @@ private BandSet bandSet = new BandSet(new Segment()) { public void pack(OutputStream outputStream) { - // TODO Auto-generated method stub - } public void unpack(InputStream inputStream) throws IOException, Pack200Exception { - // TODO Auto-generated method stub - } }; Index: src/test/java/org/apache/harmony/pack200/tests/SegmentTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/SegmentTest.java (revision 576831) +++ src/test/java/org/apache/harmony/pack200/tests/SegmentTest.java (working copy) @@ -16,10 +16,6 @@ */ package org.apache.harmony.pack200.tests; -// NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5 -// NOTE: Do not extract strings as messages; this code is still a -// work-in-progress -// NOTE: Also, don't get rid of 'else' statements for the hell of it ... import org.apache.harmony.pack200.Segment; import junit.framework.TestCase; @@ -25,19 +21,15 @@ import junit.framework.TestCase; /** - * @author Alex Blewitt - * @version $Revision: $ + * Tests for org.apache.harmony.pack200.Segment, which is the main class for pack200. */ public class SegmentTest extends TestCase { -// Commented on request in HARMONY-2246 -// Will be uncommented later -// public void testHelloWorld() throws Exception { -// assertNotNull(Segment.parse(Segment.class -// .getResourceAsStream("/org/apache/harmony/pack200/tests/HelloWorld.pack"))); -// } - /** - * @throws Exception - */ + + public void testHelloWorld() throws Exception { + assertNotNull(Segment.parse(Segment.class + .getResourceAsStream("/org/apache/harmony/pack200/tests/HelloWorld.pack"))); + } + public void testJustResources() throws Exception { assertNotNull(Segment .parse(Segment.class @@ -43,9 +35,7 @@ .parse(Segment.class .getResourceAsStream("/org/apache/harmony/pack200/tests/JustResources.pack"))); } - /** - * @throws Exception - */ + public void testJustResourcesGZip() throws Exception { assertNotNull(Segment .parse(Segment.class @@ -51,7 +41,7 @@ .parse(Segment.class .getResourceAsStream("/org/apache/harmony/pack200/tests/JustResources.pack.gz"))); } - + public void testInterfaceOnly() throws Exception { assertNotNull(Segment .parse(Segment.class @@ -58,4 +48,4 @@ .getResourceAsStream("/org/apache/harmony/pack200/tests/InterfaceOnly.pack"))); } -} +} \ No newline at end of file Index: src/test/java/org/apache/harmony/pack200/tests/BcBandsTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/BcBandsTest.java +++ src/test/java/org/apache/harmony/pack200/tests/BcBandsTest.java @@ -0,0 +1,551 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.pack200.tests; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + +import org.apache.harmony.pack200.AttrDefinitionBands; +import org.apache.harmony.pack200.AttributeLayoutMap; +import org.apache.harmony.pack200.BandSet; +import org.apache.harmony.pack200.BcBands; +import org.apache.harmony.pack200.ClassBands; +import org.apache.harmony.pack200.CpBands; +import org.apache.harmony.pack200.Pack200Exception; +import org.apache.harmony.pack200.Segment; +import org.apache.harmony.pack200.SegmentHeader; + +import junit.framework.TestCase; + +/** + * Tests for Pack200 bytecode bands + */ + +/* + * TODO: The number 8 is used in most of the tests in this class as a low + * (non-zero) number that is not likely to indicate a multiple byte number, but + * should be replaced with properly encoded byte arrays when encoding is + * implemented. + */ +public class BcBandsTest extends TestCase { + + + private int numClasses = 1; + private int[] numMethods = {1}; + + public class MockSegmentHeader extends SegmentHeader { + public int getClassCount() { + return numClasses; + } + } + + public class MockClassBands extends ClassBands { + public MockClassBands(Segment segment) { + super(segment); + } + + public long[][] getMethodFlags() { + long[][] flags = new long[numClasses][] ; + for (int i = 0; i < flags.length; i++) { + flags[i] = new long[numMethods[i]]; + } + return flags; + } + + public int[] getCodeMaxStack() { + int totalMethods = 0; + for (int i = 0; i < numClasses; i++) { + totalMethods += numMethods[i]; + } + return new int[totalMethods]; + } + + public int[] getCodeMaxNALocals() { + int totalMethods = 0; + for (int i = 0; i < numClasses; i++) { + totalMethods += numMethods[i]; + } + return new int[totalMethods]; + } + + public String[][] getMethodDescr() { + String[][] descr = new String[numClasses][]; + for (int i = 0; i < descr.length; i++) { + descr[i] = new String[numMethods[i]]; + for (int j = 0; j < descr[i].length; j++) { + descr[i][j] = "hello()"; + } + } + return descr; + } + + public ArrayList[][] getMethodAttributes() { + ArrayList[][] attributes = new ArrayList[numClasses][]; + for (int i = 0; i < attributes.length; i++) { + attributes[i] = new ArrayList[numMethods[i]]; + for (int j = 0; j < attributes[i].length; j++) { + attributes[i][j] = new ArrayList(); + } + } + return attributes; + } + } + + public class MockAttributeDefinitionBands extends AttrDefinitionBands { + + public MockAttributeDefinitionBands(Segment segment) { + super(segment); + } + + public AttributeLayoutMap getAttributeDefinitionMap() { + try { + return new AttributeLayoutMap(); + } catch (Pack200Exception e) { + fail(e.getLocalizedMessage()); + } + return null; + } + + + + } + + public class MockSegment extends Segment { + protected AttrDefinitionBands getAttrDefinitionBands() { + return new MockAttributeDefinitionBands(this); + } + + protected CpBands getCpBands() { + return new CpBands(this); + } + + protected ClassBands getClassBands() { + return new MockClassBands(this); + } + + public SegmentHeader getSegmentHeader() { + return new MockSegmentHeader(); + } + } + + BcBands bcBands = new BcBands(new MockSegment()); + + /** + * Test with single byte instructions that mean all other bands apart from + * bc_codes will be empty. + * + * @throws IOException + * @throws Pack200Exception + */ + public void testSimple() throws IOException, Pack200Exception { + byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, (byte) 128, + (byte) 129, (byte) 130, (byte) 131, (byte) 133, (byte) 134, + (byte) 135, (byte) 136, (byte) 137, (byte) 138, (byte) 139, + (byte) 140, (byte) 141, (byte) 142, (byte) 143, (byte) 144, + (byte) 145, (byte) 146, (byte) 147, (byte) 148, (byte) 149, + (byte) 150, (byte) 151, (byte) 172, (byte) 173, (byte) 174, + (byte) 175, (byte) 176, (byte) 177, (byte) 190, (byte) 191, + (byte) 194, (byte) 195, (byte) 255 }; + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(bytes.length - 1, bcBands.getMethodByteCodePacked()[0][0].length); + } + + /** + * Test with multiple classes but single byte instructions + * + * @throws IOException + * @throws Pack200Exception + */ + public void testMultipleClassesSimple() throws IOException, Pack200Exception { + numClasses = 2; + numMethods = new int[] {1,1}; + byte[] bytes = new byte[] {50, 50, (byte)255, 50, 50, (byte)255}; + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + + numClasses = 1; + numMethods = new int[] {1}; + } + + /** + * Test with multiple classes and multiple methods but single byte instructions + * @throws IOException + * @throws Pack200Exception + */ + public void testMultipleMethodsSimple() throws IOException, Pack200Exception { + numClasses = 2; + numMethods = new int[] {3,1}; + byte[] bytes = new byte[] {50, 50, (byte)255,50, 50, (byte)255, 50, 50, (byte)255, 50, 50, (byte)255}; + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + + numClasses = 1; + numMethods = new int[] {1}; + } + + + /** + * Test with codes that require entries in the bc_case_count and bc_case_value bands + * @throws Pack200Exception + * @throws IOException + */ + public void testBcCaseBands() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)170,(byte)171, (byte)255, + 2, 5, // bc_case_count + 8, 8, 8, 8, 8, 8, 8, // bc_case_value + 8, 8}; // bc_label + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_case_count = bcBands.getBcCaseCount(); + assertEquals(2, bc_case_count.length); + assertEquals(2, bc_case_count[0]); + assertEquals(5, bc_case_count[1]); + int[][] bc_case_value = bcBands.getBcCaseValue(); + assertEquals(2, bc_case_value.length); + assertEquals(2, bc_case_value[0].length); + assertEquals(5, bc_case_value[1].length); + assertEquals(2, bcBands.getBcLabel().length); + } + + /** + * Test with codes that should require entries in the bc_byte band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcByteBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {16, (byte)132, (byte)188, (byte)197, (byte)255, + 8, 8, 8, 8, // bc_byte band + 8, // bc_locals band (required by iinc (132)) + 8}; // bc_class band (required by multianewarray (197)) + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(4, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_byte = bcBands.getBcByte(); + assertEquals(4, bc_byte.length); + for (int i = 0; i < bc_byte.length; i++) { + assertEquals(8, bc_byte[i]); + } + assertEquals(1, bcBands.getBcLocal().length); + assertEquals(1, bcBands.getBcClassRef().length); + } + + /** + * Test with codes that should require entries in the bc_short band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcShortBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {17, (byte)196, (byte)132, (byte)255, + 8, 8,// bc_short band + 8, 8}; // bc_locals band (required by wide iinc (196, 132)) + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(3, bcBands.getMethodByteCodePacked()[0][0].length); + assertEquals(2, bcBands.getBcShort().length); + assertEquals(2, bcBands.getBcLocal().length); + } + + /** + * Test with codes that should require entries in the bc_local band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcLocalBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {21, 22, 23, 24, 25, + 54, 55, 56, 57, 58, (byte)169, (byte) 255, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; // bc_local band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(11, bcBands.getMethodByteCodePacked()[0][0].length); + assertEquals(11, bcBands.getBcLocal().length); + } + + /** + * Test with codes that should require entries in the bc_label band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcLabelBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte) 159, (byte) 160, (byte) 161, + (byte) 162, (byte) 163, (byte) 164, (byte) 165, (byte) 166, + (byte) 167, (byte) 168, (byte) 170, (byte) 171, (byte) 198, (byte) 199, (byte) 200, (byte) 201, (byte) 255, + 0, 0, // bc_case_count (required by tableswitch (170) and lookupswitch (171)) + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; // bc_label band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(16, bcBands.getMethodByteCodePacked()[0][0].length); + assertEquals(16, bcBands.getBcLabel().length); + } + + /** + * Test with codes that should require entries in the bc_intref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcIntRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)234, (byte)237, (byte)255, + 8, 8}; // bc_intref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_intref = bcBands.getBcIntRef(); + assertEquals(2, bc_intref.length); + } + + /** + * Test with codes that should require entries in the bc_floatref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcFloatRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)235, (byte)238, (byte)255, + 8, 8}; // bc_floatref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_floatref = bcBands.getBcFloatRef(); + assertEquals(2, bc_floatref.length); + } + + /** + * Test with codes that should require entries in the bc_longref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcLongRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {20, (byte)255, + 8}; // bc_longref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(1, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_longref = bcBands.getBcLongRef(); + assertEquals(1, bc_longref.length); + } + + /** + * Test with codes that should require entries in the bc_doubleref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcDoubleRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)239, (byte)255, + 8}; // bc_doubleref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(1, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_doubleref = bcBands.getBcDoubleRef(); + assertEquals(1, bc_doubleref.length); + } + + + /** + * Test with codes that should require entries in the bc_stringref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcStringRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {18, 19, (byte)255, + 8, 8}; // bc_stringref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_stringref = bcBands.getBcStringRef(); + assertEquals(2, bc_stringref.length); + } + + + /** + * Test with codes that should require entries in the bc_classref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcClassRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)233, (byte)236, (byte)255, + 8, 8}; // bc_classref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(2, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_classref = bcBands.getBcClassRef(); + assertEquals(2, bc_classref.length); + } + + /** + * Test with codes that should require entries in the bc_fieldref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcFieldRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)178, (byte)179, (byte)180, (byte)181, (byte)255, + 8, 8, 8, 8}; // bc_fieldref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(4, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_fieldref = bcBands.getBcFieldRef(); + assertEquals(4, bc_fieldref.length); + } + + /** + * Test with codes that should require entries in the bc_methodref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcMethodRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)182, (byte)183, (byte)184, (byte)255, + 8, 8, 8}; // bc_methodref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(3, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_methodref = bcBands.getBcMethodRef(); + assertEquals(3, bc_methodref.length); + } + + /** + * Test with codes that should require entries in the bc_imethodref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcIMethodRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)185, (byte)255, + 8}; // bc_imethodref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(1, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_imethodref = bcBands.getBcIMethodRef(); + assertEquals(1, bc_imethodref.length); + } + + /** + * Test with codes that should require entries in the bc_thisfieldref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcThisFieldBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] { (byte) 202, (byte) 203, (byte) 204, + (byte) 205, (byte) 209, (byte) 210, (byte) 211, (byte) 212, + (byte) 255, + 8, 8, 8, 8, 8, 8, 8, 8 }; // bc_thisfieldref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(8, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_thisfield = bcBands.getBcThisField(); + assertEquals(8, bc_thisfield.length); + } + + /** + * Test with codes that should require entries in the bc_superfield band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcSuperFieldBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] { (byte) 216, (byte) 217, (byte) 218, + (byte) 219, (byte) 223, (byte) 224, (byte) 225, (byte) 226, + (byte) 255, + 8, 8, 8, 8, 8, 8, 8, 8}; // bc_superfield band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(8, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_superfield = bcBands.getBcSuperField(); + assertEquals(8, bc_superfield.length); + } + + /** + * Test with codes that should require entries in the bc_thismethod band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcThisMethodBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)206, (byte)207, (byte)208, (byte)213, (byte)214, (byte)215, (byte)255, + 8, 8, 8, 8, 8, 8}; // bc_thismethod band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(6, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_thismethod = bcBands.getBcThisMethod(); + assertEquals(6, bc_thismethod.length); + } + + /** + * Test with codes that should require entries in the bc_supermethod band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcSuperMethodBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)220, (byte)221, (byte)222, (byte)227, (byte)228, (byte)229, (byte)255, + 8, 8, 8, 8, 8, 8}; // bc_supermethod band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(6, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_supermethod = bcBands.getBcSuperMethod(); + assertEquals(6, bc_supermethod.length); + } + + /** + * Test with codes that should require entries in the bc_initrefref band + * + * @throws Pack200Exception + * @throws IOException + */ + public void testBcInitRefRefBand() throws IOException, Pack200Exception { + byte[] bytes = new byte[] {(byte)230, (byte)231, (byte)232, (byte)255, + 8, 8, 8}; // bc_initrefref band + InputStream in = new ByteArrayInputStream(bytes); + bcBands.unpack(in); + assertEquals(3, bcBands.getMethodByteCodePacked()[0][0].length); + int[] bc_initrefref = bcBands.getBcInitRef(); + assertEquals(3, bc_initrefref.length); + } + + public void testBcEscRefBands() throws IOException, Pack200Exception { + // TODO + } + + public void testBcEscBands() throws IOException, Pack200Exception { + // TODO + } + +}