You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by hi...@apache.org on 2009/06/17 16:00:28 UTC
svn commit: r785606 [2/4] - in /harmony/enhanced/classlib/branches/java6: ./
make/ modules/archive/src/main/java/java/util/jar/
modules/archive/src/main/java/java/util/zip/
modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/
m...
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java Wed Jun 17 14:00:24 2009
@@ -24,9 +24,11 @@
import java.util.List;
import java.util.Map;
+import org.objectweb.asm.Attribute;
+
/**
- * Attribute Definition bands define how any unknown attributes should be
- * read by the decompressor.
+ * Attribute Definition bands define how any unknown attributes should be read
+ * by the decompressor.
*/
public class AttributeDefinitionBands extends BandSet {
@@ -35,98 +37,132 @@
public static final int CONTEXT_FIELD = 1;
public static final int CONTEXT_METHOD = 2;
- private final Map layouts = new HashMap();
-
- private final Map classAttributes = new HashMap();
- private final Map methodAttributes = new HashMap();
- private final Map fieldAttributes = new HashMap();
- private final Map codeAttributes = new HashMap();
+ private final List classAttributeLayouts = new ArrayList();
+ private final List methodAttributeLayouts = new ArrayList();
+ private final List fieldAttributeLayouts = new ArrayList();
+ private final List codeAttributeLayouts = new ArrayList();
private final List attributeDefinitions = new ArrayList();
private final CpBands cpBands;
private final Segment segment;
- public AttributeDefinitionBands(Segment segment, int effort) {
+ public AttributeDefinitionBands(Segment segment, int effort,
+ Attribute[] attributePrototypes) {
super(effort, segment.getSegmentHeader());
this.cpBands = segment.getCpBands();
this.segment = segment;
- }
-
- public void finaliseBands() {
- addSyntheticDefinitions();
- segmentHeader.setAttribute_definition_count(classAttributes.keySet()
- .size()
- + methodAttributes.keySet().size()
- + fieldAttributes.keySet().size()
- + codeAttributes.keySet().size()
- + attributeDefinitions.size());
- if (classAttributes.keySet().size() > 7) {
+ Map classLayouts = new HashMap();
+ Map methodLayouts = new HashMap();
+ Map fieldLayouts = new HashMap();
+ Map codeLayouts = new HashMap();
+
+ for (int i = 0; i < attributePrototypes.length; i++) {
+ NewAttribute newAttribute = (NewAttribute) attributePrototypes[i];
+ if (newAttribute.isContextClass()) {
+ classLayouts.put(newAttribute.type, newAttribute.getLayout());
+ }
+ if (newAttribute.isContextMethod()) {
+ methodLayouts.put(newAttribute.type, newAttribute.getLayout());
+ }
+ if (newAttribute.isContextField()) {
+ fieldLayouts.put(newAttribute.type, newAttribute.getLayout());
+ }
+ if (newAttribute.isContextCode()) {
+ codeLayouts.put(newAttribute.type, newAttribute.getLayout());
+ }
+ }
+ if (classLayouts.keySet().size() > 7) {
segmentHeader.setHave_class_flags_hi(true);
}
- if(methodAttributes.keySet().size() > 6) {
+ if (methodLayouts.keySet().size() > 6) {
segmentHeader.setHave_method_flags_hi(true);
}
- if(fieldAttributes.keySet().size() > 10) {
+ if (fieldLayouts.keySet().size() > 10) {
segmentHeader.setHave_field_flags_hi(true);
}
- if(codeAttributes.keySet().size() > 15) {
+ if (codeLayouts.keySet().size() > 15) {
segmentHeader.setHave_code_flags_hi(true);
}
- }
-
- public void pack(OutputStream out) throws IOException, Pack200Exception {
- int[] availableClassIndices = new int[] {25, 26, 27, 28, 29, 30, 31};
- if(classAttributes.size() > 7) {
+ int[] availableClassIndices = new int[] { 25, 26, 27, 28, 29, 30, 31 };
+ if (classLayouts.size() > 7) {
availableClassIndices = addHighIndices(availableClassIndices);
}
- addAttributeDefinitions(classAttributes, availableClassIndices, CONTEXT_CLASS);
- int[] availableMethodIndices = new int[] {26, 27, 28, 29, 30, 31};
- if(methodAttributes.size() > 6) {
+ addAttributeDefinitions(classLayouts, availableClassIndices,
+ CONTEXT_CLASS);
+ int[] availableMethodIndices = new int[] { 26, 27, 28, 29, 30, 31 };
+ if (methodAttributeLayouts.size() > 6) {
availableMethodIndices = addHighIndices(availableMethodIndices);
}
- addAttributeDefinitions(methodAttributes, availableMethodIndices, CONTEXT_METHOD);
- int[] availableFieldIndices = new int[] {18, 23, 24, 25, 26, 27, 28, 29, 30, 31};
- if(fieldAttributes.size() > 10) {
+ addAttributeDefinitions(methodLayouts, availableMethodIndices,
+ CONTEXT_METHOD);
+ int[] availableFieldIndices = new int[] { 18, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31 };
+ if (fieldAttributeLayouts.size() > 10) {
availableFieldIndices = addHighIndices(availableFieldIndices);
}
- addAttributeDefinitions(fieldAttributes, availableFieldIndices, CONTEXT_FIELD);
- int[] availableCodeIndices = new int[] {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
- if(codeAttributes.size() > 15) {
+ addAttributeDefinitions(fieldLayouts, availableFieldIndices,
+ CONTEXT_FIELD);
+ int[] availableCodeIndices = new int[] { 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31 };
+ if (codeAttributeLayouts.size() > 15) {
availableCodeIndices = addHighIndices(availableCodeIndices);
}
- addAttributeDefinitions(codeAttributes, availableCodeIndices, CONTEXT_CODE);
+ addAttributeDefinitions(codeLayouts, availableCodeIndices, CONTEXT_CODE);
+ }
+ /**
+ * All input classes for the segment have now been read in, so this method
+ * is called so that this class can calculate/complete anything it could not
+ * do while classes were being read.
+ */
+ public void finaliseBands() {
+ addSyntheticDefinitions();
+ segmentHeader.setAttribute_definition_count(attributeDefinitions.size());
+ }
+
+ public void pack(OutputStream out) throws IOException, Pack200Exception {
int[] attributeDefinitionHeader = new int[attributeDefinitions.size()];
int[] attributeDefinitionName = new int[attributeDefinitions.size()];
int[] attributeDefinitionLayout = new int[attributeDefinitions.size()];
for (int i = 0; i < attributeDefinitionLayout.length; i++) {
- AttributeDefinition def = (AttributeDefinition) attributeDefinitions.get(i);
- attributeDefinitionHeader[i] = def.contextType | (def.index + 1 << 2);
+ AttributeDefinition def = (AttributeDefinition) attributeDefinitions
+ .get(i);
+ attributeDefinitionHeader[i] = def.contextType
+ | (def.index + 1 << 2);
attributeDefinitionName[i] = def.name.getIndex();
attributeDefinitionLayout[i] = def.layout.getIndex();
}
- out.write(encodeBandInt("attributeDefinitionHeader", attributeDefinitionHeader, Codec.BYTE1));
- out.write(encodeBandInt("attributeDefinitionName", attributeDefinitionName, Codec.UNSIGNED5));
- out.write(encodeBandInt("attributeDefinitionLayout", attributeDefinitionLayout, Codec.UNSIGNED5));
+ out.write(encodeBandInt("attributeDefinitionHeader",
+ attributeDefinitionHeader, Codec.BYTE1));
+ out.write(encodeBandInt("attributeDefinitionName",
+ attributeDefinitionName, Codec.UNSIGNED5));
+ out.write(encodeBandInt("attributeDefinitionLayout",
+ attributeDefinitionLayout, Codec.UNSIGNED5));
}
private void addSyntheticDefinitions() {
- boolean anySytheticClasses = segment.getClassBands().isAnySyntheticClasses();
- boolean anySyntheticMethods = segment.getClassBands().isAnySyntheticMethods();
- boolean anySyntheticFields = segment.getClassBands().isAnySyntheticFields();
- if(anySytheticClasses || anySyntheticMethods || anySyntheticFields) {
+ boolean anySytheticClasses = segment.getClassBands()
+ .isAnySyntheticClasses();
+ boolean anySyntheticMethods = segment.getClassBands()
+ .isAnySyntheticMethods();
+ boolean anySyntheticFields = segment.getClassBands()
+ .isAnySyntheticFields();
+ if (anySytheticClasses || anySyntheticMethods || anySyntheticFields) {
CPUTF8 syntheticUTF = cpBands.getCPUtf8("Synthetic");
CPUTF8 emptyUTF = cpBands.getCPUtf8("");
- if(anySytheticClasses) {
- attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_CLASS, syntheticUTF, emptyUTF));
+ if (anySytheticClasses) {
+ attributeDefinitions.add(new AttributeDefinition(12,
+ CONTEXT_CLASS, syntheticUTF, emptyUTF));
}
- if(anySyntheticMethods) {
- attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_METHOD, syntheticUTF, emptyUTF));
+ if (anySyntheticMethods) {
+ attributeDefinitions.add(new AttributeDefinition(12,
+ CONTEXT_METHOD, syntheticUTF, emptyUTF));
}
- if(anySyntheticFields) {
- attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_FIELD, syntheticUTF, emptyUTF));
+ if (anySyntheticFields) {
+ attributeDefinitions.add(new AttributeDefinition(12,
+ CONTEXT_FIELD, syntheticUTF, emptyUTF));
}
}
}
@@ -137,29 +173,58 @@
temp[i] = availableIndices[i];
}
int j = 32;
- for (int i = availableIndices.length; i < temp.length ; i++) {
+ for (int i = availableIndices.length; i < temp.length; i++) {
temp[i] = j;
j++;
}
return temp;
}
- private void addAttributeDefinitions(Map attributes,
- int[] availableIndices, int contextType) {
+ private void addAttributeDefinitions(Map layouts, int[] availableIndices,
+ int contextType) {
int i = 0;
- for (Iterator iterator = attributes.keySet().iterator(); iterator.hasNext();) {
+ for (Iterator iterator = layouts.keySet().iterator(); iterator
+ .hasNext();) {
String name = (String) iterator.next();
String layout = (String) layouts.get(name);
int index = availableIndices[i];
- attributeDefinitions.add(new AttributeDefinition(index, contextType, cpBands.getCPUtf8(name), cpBands.getCPUtf8(layout)));
+ AttributeDefinition definition = new AttributeDefinition(index,
+ contextType, cpBands.getCPUtf8(name), cpBands
+ .getCPUtf8(layout));
+ attributeDefinitions.add(definition);
+ switch (contextType) {
+ case CONTEXT_CLASS:
+ classAttributeLayouts.add(definition);
+ break;
+ case CONTEXT_METHOD:
+ methodAttributeLayouts.add(definition);
+ break;
+ case CONTEXT_FIELD:
+ fieldAttributeLayouts.add(definition);
+ break;
+ case CONTEXT_CODE:
+ codeAttributeLayouts.add(definition);
+ }
}
}
- public void addLayout(String name, String layout) {
- layouts.put(name, layout);
+ public List getClassAttributeLayouts() {
+ return classAttributeLayouts;
+ }
+
+ public List getMethodAttributeLayouts() {
+ return methodAttributeLayouts;
+ }
+
+ public List getFieldAttributeLayouts() {
+ return fieldAttributeLayouts;
+ }
+
+ public List getCodeAttributeLayouts() {
+ return codeAttributeLayouts;
}
- private static class AttributeDefinition {
+ public static class AttributeDefinition {
public int index;
public int contextType;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BHSDCodec.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BHSDCodec.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BHSDCodec.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BHSDCodec.java Wed Jun 17 14:00:24 2009
@@ -204,14 +204,14 @@
return cardinality;
}
- public long decode(InputStream in) throws IOException, Pack200Exception {
+ public int decode(InputStream in) throws IOException, Pack200Exception {
if (d != 0)
throw new Pack200Exception(
"Delta encoding used without passing in last value; this is a coding error");
return decode(in, 0);
}
- public long decode(InputStream in, long last) throws IOException,
+ public int decode(InputStream in, long last) throws IOException,
Pack200Exception {
int n = 0;
long z = 0;
@@ -219,6 +219,7 @@
do {
x = in.read();
+ lastBandLength ++;
z += x * powers[n];
n++;
} while (x >= l && n < b);
@@ -252,7 +253,39 @@
// }
if (isDelta())
z += last;
- return z;
+ return (int)z;
+ }
+
+ public int[] decodeInts(int n, InputStream in) throws IOException,
+ Pack200Exception {
+ int[] band = super.decodeInts(n, in);
+ if (isDelta()) {
+ for (int i = 0; i < band.length; i++) {
+ while (band[i] > largest) {
+ band[i] -= cardinality;
+ }
+ while (band[i] < smallest) {
+ band[i] += cardinality;
+ }
+ }
+ }
+ return band;
+ }
+
+ public int[] decodeInts(int n, InputStream in, int firstValue)
+ throws IOException, Pack200Exception {
+ int[] band = super.decodeInts(n, in, firstValue);
+ if (isDelta()) {
+ for (int i = 0; i < band.length; i++) {
+ while (band[i] > largest) {
+ band[i] -= cardinality;
+ }
+ while (band[i] < smallest) {
+ band[i] += cardinality;
+ }
+ }
+ }
+ return band;
}
// private long cast32(long u) {
@@ -269,19 +302,19 @@
* @return <code>true</code> if the encoding can encode this value
*/
public boolean encodes(long value) {
- return (value >= smallest && value <= largest);
+ return value >= smallest && value <= largest;
}
- public byte[] encode(long value, long last) throws Pack200Exception {
- if (isDelta()) {
- value -= last;
+ public byte[] encode(int value, int last) throws Pack200Exception {
+ if(!encodes(value)) {
+ throw new Pack200Exception("The codec " + toString()
+ + " does not encode the value " + value);
}
- // TODO: Do we need this? this implementation isn't right because of integer overflow...
-// if (!encodes(value)) {
-// throw new Pack200Exception("The codec " + toString()
-// + " does not encode the value " + value);
-// }
+
long z = value;
+ if (isDelta()) {
+ z -= last;
+ }
if (isSigned()) {
if(z < Integer.MIN_VALUE) {
z += 4294967296L;
@@ -301,12 +334,16 @@
if (z < 0) {
// Need to use integer overflow here to represent negatives.
if(cardinality < 4294967296L) {
- z+= cardinality;
+ z += cardinality;
} else {
z += 4294967296L; // this value is equal to (1 << 32).
}
}
}
+ if (z < 0) {
+ throw new Pack200Exception("unable to encode");
+ }
+
List byteList = new ArrayList();
for (int n = 0; n < b; n++) {
long byteN;
@@ -331,7 +368,7 @@
return bytes;
}
- public byte[] encode(long value) throws Pack200Exception {
+ public byte[] encode(int value) throws Pack200Exception {
return encode(value, 0);
}
@@ -393,19 +430,16 @@
private long calculateSmallest() {
long result;
- if (d == 1) {
- BHSDCodec bh0 = new BHSDCodec(b, h);
- return bh0.smallest();
- } else if (isSigned()) {
- result = -cardinality() / (1 << s);
- } else {
- if (cardinality > Integer.MAX_VALUE) {
+ if (d == 1 || !isSigned()) {
+ if (cardinality >= 4294967296L) { // 2^32
result = Integer.MIN_VALUE;
} else {
result = 0;
}
+ } else {
+ result = Math.max(Integer.MIN_VALUE, -cardinality() / (1 << s));
}
- return Math.max(Integer.MIN_VALUE, result);
+ return result;
}
/**
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java Wed Jun 17 14:00:24 2009
@@ -18,49 +18,117 @@
import java.io.IOException;
import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
-
+/**
+ * Abstract superclass for a set of bands
+ */
public abstract class BandSet {
- private final int effort;
protected final SegmentHeader segmentHeader;
+ final int effort;
+ // Minimum size of band for each effort level where we consider alternative codecs
+ // Note: these values have been tuned - please test carefully if changing them
+ private final int[] effortThresholds = new int[] {0, 0, 1000, 500, 100, 100, 100, 100, 100, 0};
+
+ private long[] canonicalLargest;
+ private long[] canonicalSmallest;
+
+ /**
+ * Create a new BandSet
+ * @param effort - the packing effort to be used (must be 1-9)
+ * @param header - the segment header
+ */
public BandSet(int effort, SegmentHeader header) {
this.effort = effort;
this.segmentHeader = header;
}
+ /**
+ * Write the packed set of bands to the given output stream
+ * @param out
+ * @throws IOException
+ * @throws Pack200Exception
+ */
public abstract void pack(OutputStream out) throws IOException, Pack200Exception;
+ /**
+ * Encode a band without considering other Codecs
+ * @param band - the band
+ * @param codec - the Codec to use
+ * @return the encoded band
+ * @throws Pack200Exception
+ */
public byte[] encodeScalar(int[] band, BHSDCodec codec) throws Pack200Exception {
return codec.encode(band);
}
+ /**
+ * Encode a single value with the given Codec
+ * @param value - the value to encode
+ * @param codec - Codec to use
+ * @return the encoded value
+ * @throws Pack200Exception
+ */
public byte[] encodeScalar(int value, BHSDCodec codec) throws Pack200Exception {
return codec.encode(value);
}
+ /**
+ * Encode a band of integers. The default codec may be used, but other
+ * Codecs are considered if effort is greater than 1.
+ *
+ * @param name
+ * - name of the band (used for debugging)
+ * @param ints
+ * - the band
+ * @param defaultCodec
+ * - the default Codec
+ * @return the encoded band
+ * @throws Pack200Exception
+ */
public byte[] encodeBandInt(String name, int[] ints, BHSDCodec defaultCodec) throws Pack200Exception {
- if(effort > 1 && (ints.length > 99 || effort == 9)) {
- Codec betterCodec = lookForBetterCodec(name, ints, defaultCodec);
+ byte[] encodedBand = null;
+ // Useful for debugging
+// if(ints.length > 0) {
+// System.out.println("encoding " + name + " " + ints.length);
+// }
+ if(effort > 1 && (ints.length >= effortThresholds[effort])) {
+ BandAnalysisResults results = analyseBand(name, ints, defaultCodec);
+ Codec betterCodec = results.betterCodec;
+ encodedBand = results.encodedBand;
if(betterCodec != null) {
if(betterCodec instanceof BHSDCodec) {
int[] specifierBand = CodecEncoding.getSpecifier(betterCodec, defaultCodec);
int specifier = specifierBand[0];
- if(specifierBand.length > 0) {
+ if(specifierBand.length > 1) {
for (int i = 1; i < specifierBand.length; i++) {
segmentHeader.appendBandCodingSpecifier(specifierBand[i]);
}
}
+ if(defaultCodec.isSigned()) {
+ specifier = -1 -specifier;
+ } else {
+ specifier = specifier + defaultCodec.getL();
+ }
byte[] specifierEncoded = defaultCodec.encode(new int[] {specifier});
- byte[] rest = betterCodec.encode(ints);
- byte[] band = new byte[specifierEncoded.length + rest.length];
+ byte[] band = new byte[specifierEncoded.length + encodedBand.length];
System.arraycopy(specifierEncoded, 0, band, 0, specifierEncoded.length);
- System.arraycopy(rest, 0, band, specifierEncoded.length, rest.length);
+ System.arraycopy(encodedBand, 0, band, specifierEncoded.length, encodedBand.length);
return band;
} else if (betterCodec instanceof PopulationCodec) {
-
+ int[] extraSpecifierInfo = results.extraMetadata;
+ for (int i = 0; i < extraSpecifierInfo.length; i++) {
+ segmentHeader.appendBandCodingSpecifier(extraSpecifierInfo[i]);
+ }
+ return encodedBand;
} else if (betterCodec instanceof RunCodec) {
}
@@ -69,39 +137,209 @@
// If we get here then we've decided to use the default codec.
if(ints.length > 0) {
-// System.out.println("encoding " + name + ", size = " + ints.length);
+ if(encodedBand == null) {
+ encodedBand = defaultCodec.encode(ints);
+ }
int first = ints[0];
if(defaultCodec.getB() != 1) {
if (defaultCodec.isSigned() && first >= -256 && first <= -1) {
int specifier = -1 - CodecEncoding.getSpecifierForDefaultCodec(defaultCodec);
byte[] specifierEncoded = defaultCodec.encode(new int[] {specifier});
- byte[] rest = defaultCodec.encode(ints);
- byte[] band = new byte[specifierEncoded.length + rest.length];
+ byte[] band = new byte[specifierEncoded.length + encodedBand.length];
System.arraycopy(specifierEncoded, 0, band, 0, specifierEncoded.length);
- System.arraycopy(rest, 0, band, specifierEncoded.length, rest.length);
+ System.arraycopy(encodedBand, 0, band, specifierEncoded.length, encodedBand.length);
return band;
} else if (!defaultCodec.isSigned() && first >= defaultCodec.getL()
&& first <= defaultCodec.getL() + 255) {
int specifier = CodecEncoding.getSpecifierForDefaultCodec(defaultCodec) + defaultCodec.getL();
byte[] specifierEncoded = defaultCodec.encode(new int[] {specifier});
- byte[] rest = defaultCodec.encode(ints);
- byte[] band = new byte[specifierEncoded.length + rest.length];
+ byte[] band = new byte[specifierEncoded.length + encodedBand.length];
System.arraycopy(specifierEncoded, 0, band, 0, specifierEncoded.length);
- System.arraycopy(rest, 0, band, specifierEncoded.length, rest.length);
+ System.arraycopy(encodedBand, 0, band, specifierEncoded.length, encodedBand.length);
return band;
}
}
- return defaultCodec.encode(ints);
+ return encodedBand;
}
return new byte[0];
}
- private Codec lookForBetterCodec(String name, int[] ints,
- BHSDCodec defaultCodec) {
- // TODO Auto-generated method stub
- return null;
+ private BandAnalysisResults analyseBand(String name, int[] band,
+ BHSDCodec defaultCodec) throws Pack200Exception {
+
+ BandAnalysisResults results = new BandAnalysisResults();
+
+ if(canonicalLargest == null) {
+ canonicalLargest = new long[116];
+ canonicalSmallest = new long[116];
+ for (int i = 1; i < canonicalLargest.length; i++) {
+ canonicalLargest[i] = CodecEncoding.getCanonicalCodec(i).largest();
+ canonicalSmallest[i] = CodecEncoding.getCanonicalCodec(i).smallest();
+ }
+ }
+ BandData bandData = new BandData(band);
+
+ // Check that there is a reasonable saving to be made
+ byte[] encoded = defaultCodec.encode(band);
+ results.encodedBand = encoded;
+
+ // Note: these values have been tuned - please test carefully if changing them
+ if(encoded.length <= band.length + 23 - 2*effort) { // TODO: tweak
+ return results;
+ }
+
+ // Check if we can use BYTE1 as that's a 1:1 mapping if we can
+ if(!bandData.anyNegatives() && bandData.largest <= Codec.BYTE1.largest()) {
+ results.encodedBand = Codec.BYTE1.encode(band) ;
+ results.betterCodec = Codec.BYTE1;
+ return results;
+ }
+
+ // Consider a population codec (but can't be nested)
+ if(effort > 3 && !name.equals("POPULATION")) {
+ int numDistinctValues = bandData.numDistinctValues();
+ float distinctValuesAsProportion = (float)numDistinctValues / (float)band.length;
+
+ // Note: these values have been tuned - please test carefully if changing them
+ if(numDistinctValues < 100 || distinctValuesAsProportion < 0.02 || (effort > 6 && distinctValuesAsProportion < 0.04)) { // TODO: tweak
+ encodeWithPopulationCodec(name, band, defaultCodec, bandData, results);
+ if(timeToStop(results)) {
+ return results;
+ }
+ }
+ }
+
+ List codecFamiliesToTry = new ArrayList();
+
+ // See if the deltas are mainly small increments
+ if(bandData.mainlyPositiveDeltas() && bandData.mainlySmallDeltas()) {
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs2);
+ }
+
+ if (bandData.wellCorrelated()) { // Try delta encodings
+ if (bandData.mainlyPositiveDeltas()) {
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs3);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs4);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs5);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs3);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs4);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs5);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs2);
+ } else {
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs3);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs2);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs4);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs5);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaSignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaSignedCodecs2);
+ }
+ } else {
+ if (bandData.anyNegatives()) {
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaSignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaSignedCodecs2);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs2);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs3);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs4);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaSignedCodecs5);
+ } else {
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs3);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs4);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs5);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.nonDeltaUnsignedCodecs2);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs1);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs3);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs4);
+ codecFamiliesToTry.add(CanonicalCodecFamilies.deltaUnsignedCodecs5);
+ }
+ }
+ if(name.equalsIgnoreCase("cpint")) {
+ System.out.print("");
+ }
+
+ for (Iterator iterator = codecFamiliesToTry.iterator(); iterator
+ .hasNext();) {
+ BHSDCodec[] family = (BHSDCodec[]) iterator.next();
+ tryCodecs(name, band, defaultCodec, bandData, results, encoded,
+ family);
+ if (timeToStop(results)) {
+ break;
+ }
+ }
+
+ return results;
}
+ private boolean timeToStop(BandAnalysisResults results) {
+ // if tried more than effort number of codecs for this band then return
+ // Note: these values have been tuned - please test carefully if changing them
+ if(effort > 6) {
+ return results.numCodecsTried >= effort * 2;
+ }
+ return results.numCodecsTried >= effort;
+ // May want to also check how much we've saved if performance needs improving, e.g. saved more than effort*2 %
+ // || (float)results.saved/(float)results.encodedBand.length > (float)effort * 2/100;
+ }
+
+ private void tryCodecs(String name, int[] band, BHSDCodec defaultCodec, BandData bandData,
+ BandAnalysisResults results, byte[] encoded,
+ BHSDCodec[] potentialCodecs) throws Pack200Exception {
+ for (int i = 0; i < potentialCodecs.length; i++) {
+ BHSDCodec potential = potentialCodecs[i];
+ if(potential.equals(defaultCodec)) {
+ return; // don't try codecs with greater cardinality in the same 'family' as the default codec as there won't be any savings
+ }
+ if (potential.isDelta()) {
+ if (potential.largest() >= bandData.largestDelta
+ && potential.smallest() <= bandData.smallestDelta
+ && potential.largest() >= bandData.largest
+ && potential.smallest() <= bandData.smallest) {
+ // TODO: can represent some negative deltas with overflow
+ byte[] encoded2 = potential.encode(band);
+ results.numCodecsTried++;
+ byte[] specifierEncoded = defaultCodec.encode(CodecEncoding
+ .getSpecifier(potential, null));
+ int saved = encoded.length - encoded2.length
+ - specifierEncoded.length;
+ if (saved > results.saved) {
+ results.betterCodec = potential;
+ results.encodedBand = encoded2;
+ results.saved = saved;
+ }
+ }
+ } else if (potential.largest() >= bandData.largest
+ && potential.smallest() <= bandData.smallest) {
+ byte[] encoded2 = potential.encode(band);
+ results.numCodecsTried++;
+ byte[] specifierEncoded = defaultCodec.encode(CodecEncoding
+ .getSpecifier(potential, null));
+ int saved = encoded.length - encoded2.length
+ - specifierEncoded.length;
+ if (saved > results.saved) {
+ results.betterCodec = potential;
+ results.encodedBand = encoded2;
+ results.saved = saved;
+ }
+ }
+ if(timeToStop(results)) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Returns true if the name of the source file can be predicted from the
+ * class name
+ *
+ * @param className
+ * the class name
+ * @param sourceFileName
+ * the source file name
+ */
public boolean isPredictableSourceFileName(String className, String sourceFileName) {
if (className.indexOf('.') != -1) {
className = className.substring(className.lastIndexOf('.') + 1);
@@ -113,6 +351,218 @@
return className.equals(sourceFileName);
}
+// This could be useful if further enhancements are done but is not currently used
+//
+// private void encodeWithRunCodec(String name, int[] band, int index,
+// BHSDCodec defaultCodec, BandData bandData,
+// BandAnalysisResults results) throws Pack200Exception {
+// int[] firstBand = new int[index];
+// int[] secondBand = new int[band.length - index];
+// System.arraycopy(band, 0, firstBand, 0, index);
+// System.arraycopy(band, index, secondBand, 0, secondBand.length);
+// BandAnalysisResults firstResults = analyseBand(name + "A", firstBand, defaultCodec);
+// BandAnalysisResults secondResults = analyseBand(name + "B", secondBand, defaultCodec);
+// int specifier = 117;
+// byte[] specifierEncoded = defaultCodec.encode(new int[] {specifier});
+// int totalLength = firstResults.encodedBand.length + secondResults.encodedBand.length + specifierEncoded.length + 4; // TODO actual
+// if(totalLength < results.encodedBand.length) {
+// System.out.println("using run codec");
+// results.saved += results.encodedBand.length - totalLength;
+// byte[] encodedBand = new byte[specifierEncoded.length + firstResults.encodedBand.length + secondResults.encodedBand.length];
+// System.arraycopy(specifierEncoded, 0, encodedBand, 0, specifierEncoded.length);
+// System.arraycopy(firstResults.encodedBand, 0, encodedBand, specifierEncoded.length, firstResults.encodedBand.length);
+// System.arraycopy(secondResults.encodedBand, 0, encodedBand, specifierEncoded.length + firstResults.encodedBand.length, secondResults.encodedBand.length);
+// results.encodedBand = encodedBand;
+// results.betterCodec = new RunCodec(index, firstResults.betterCodec, secondResults.betterCodec);
+// }
+// }
+
+ private void encodeWithPopulationCodec(String name, int[] band,
+ BHSDCodec defaultCodec, BandData bandData, BandAnalysisResults results) throws Pack200Exception {
+ results.numCodecsTried += 3; // quite a bit more effort to try this codec
+ final Map distinctValues = bandData.distinctValues;
+
+ List favoured = new ArrayList();
+ for (Iterator iterator = distinctValues.keySet().iterator(); iterator
+ .hasNext();) {
+ Integer value = (Integer) iterator.next();
+ Integer count = (Integer) distinctValues.get(value);
+ if(count.intValue() > 2 || distinctValues.size() < 256) { // TODO: tweak
+ favoured.add(value);
+ }
+ }
+
+ // Sort the favoured list with the most commonly occurring first
+ if(distinctValues.size() > 255) {
+ Collections.sort(favoured, new Comparator() {
+ public int compare(Object arg0, Object arg1) {
+ return ((Integer)distinctValues.get(arg1)).compareTo((Integer)distinctValues.get(arg0));
+ }
+ });
+ }
+
+ IntList unfavoured = new IntList();
+ Map favouredToIndex = new HashMap();
+ for (int i = 0; i < favoured.size(); i++) {
+ Integer value = (Integer) favoured.get(i);
+ favouredToIndex.put(value, new Integer(i));
+ }
+
+ int[] tokens = new int[band.length];
+ for (int i = 0; i < band.length; i++) {
+ Integer favouredIndex = (Integer)favouredToIndex.get(new Integer(band[i]));
+ if(favouredIndex == null) {
+ tokens[i] = 0;
+ unfavoured.add(band[i]);
+ } else {
+ tokens[i] = favouredIndex.intValue() + 1;
+ }
+ }
+ favoured.add(favoured.get(favoured.size() - 1)); // repeat last value
+ int[] favouredBand = listToArray(favoured);
+ int[] unfavouredBand = unfavoured.toArray();
+
+ // Analyse the three bands to get the best codec
+ BandAnalysisResults favouredResults = analyseBand("POPULATION", favouredBand, defaultCodec);
+ BandAnalysisResults unfavouredResults = analyseBand("POPULATION", unfavouredBand, defaultCodec);
+
+ int tdefL = 0;
+ int l = 0;
+ Codec tokenCodec = null;
+ byte[] tokensEncoded;
+ int k = favoured.size() - 1;
+ if(k < 256) {
+ tdefL = 1;
+ tokensEncoded = Codec.BYTE1.encode(tokens);
+ } else {
+ BandAnalysisResults tokenResults = analyseBand("POPULATION", tokens, defaultCodec);
+ tokenCodec = tokenResults.betterCodec;
+ tokensEncoded = tokenResults.encodedBand;
+ if(tokenCodec == null) {
+ tokenCodec = defaultCodec;
+ }
+ l = ((BHSDCodec) tokenCodec).getL();
+ int h = ((BHSDCodec) tokenCodec).getH();
+ int s = ((BHSDCodec) tokenCodec).getS();
+ int b = ((BHSDCodec) tokenCodec).getB();
+ int d = ((BHSDCodec) tokenCodec).isDelta() ? 1 : 0;
+ if(s == 0 && d == 0) {
+ boolean canUseTDefL = true;
+ if(b > 1) {
+ BHSDCodec oneLowerB = new BHSDCodec(b-1, h);
+ if(oneLowerB.largest() >= k) {
+ canUseTDefL = false;
+ }
+ }
+ if(canUseTDefL) {
+ switch (l) {
+ case 4:
+ tdefL = 1;
+ break;
+ case 8:
+ tdefL = 2;
+ break;
+ case 16:
+ tdefL = 3;
+ break;
+ case 32:
+ tdefL = 4;
+ break;
+ case 64:
+ tdefL = 5;
+ break;
+ case 128:
+ tdefL = 6;
+ break;
+ case 192:
+ tdefL = 7;
+ break;
+ case 224:
+ tdefL = 8;
+ break;
+ case 240:
+ tdefL = 9;
+ break;
+ case 248:
+ tdefL = 10;
+ break;
+ case 252:
+ tdefL = 11;
+ break;
+ }
+ }
+ }
+ }
+
+ byte[] favouredEncoded = favouredResults.encodedBand;
+ byte[] unfavouredEncoded = unfavouredResults.encodedBand;
+ Codec favouredCodec = favouredResults.betterCodec;
+ Codec unfavouredCodec = unfavouredResults.betterCodec;
+
+ int specifier = 141 + (favouredCodec == null ? 1 : 0) + (4 * tdefL) + (unfavouredCodec == null ? 2 : 0);
+ IntList extraBandMetadata = new IntList(3);
+ if(favouredCodec != null) {
+ int[] specifiers = CodecEncoding.getSpecifier(favouredCodec, null);
+ for (int i = 0; i < specifiers.length; i++) {
+ extraBandMetadata.add(specifiers[i]);
+ }
+ }
+ if(tdefL == 0) {
+ int[] specifiers = CodecEncoding.getSpecifier(tokenCodec, null);
+ for (int i = 0; i < specifiers.length; i++) {
+ extraBandMetadata.add(specifiers[i]);
+ }
+ }
+ if(unfavouredCodec != null) {
+ int[] specifiers = CodecEncoding.getSpecifier(unfavouredCodec, null);
+ for (int i = 0; i < specifiers.length; i++) {
+ extraBandMetadata.add(specifiers[i]);
+ }
+ }
+ int[] extraMetadata = extraBandMetadata.toArray();
+ byte[] extraMetadataEncoded = Codec.UNSIGNED5.encode(extraMetadata);
+ if(defaultCodec.isSigned()) {
+ specifier = -1 -specifier;
+ } else {
+ specifier = specifier + defaultCodec.getL();
+ }
+ byte[] firstValueEncoded = defaultCodec.encode(new int[] {specifier});
+ int totalBandLength = firstValueEncoded.length + favouredEncoded.length + tokensEncoded.length + unfavouredEncoded.length;
+
+ if(totalBandLength + extraMetadataEncoded.length < results.encodedBand.length) {
+ results.saved += results.encodedBand.length - (totalBandLength + extraMetadataEncoded.length);
+ byte[] encodedBand = new byte[totalBandLength];
+ System.arraycopy(firstValueEncoded, 0, encodedBand, 0, firstValueEncoded.length);
+ System.arraycopy(favouredEncoded, 0, encodedBand, firstValueEncoded.length, favouredEncoded.length);
+ System.arraycopy(tokensEncoded, 0, encodedBand, firstValueEncoded.length + favouredEncoded.length, tokensEncoded.length);
+ System.arraycopy(unfavouredEncoded, 0, encodedBand, firstValueEncoded.length + favouredEncoded.length + tokensEncoded.length, unfavouredEncoded.length);
+ results.encodedBand = encodedBand;
+ results.extraMetadata = extraMetadata;
+ if(l != 0) {
+ results.betterCodec = new PopulationCodec(favouredCodec, l, unfavouredCodec);
+ } else {
+ results.betterCodec = new PopulationCodec(favouredCodec, tokenCodec, unfavouredCodec);
+ }
+ }
+ }
+
+ /**
+ * Encode a band of longs (values are split into their high and low 32 bits
+ * and then encoded as two separate bands
+ *
+ * @param name
+ * - name of the band (for debugging purposes)
+ * @param flags
+ * - the band
+ * @param loCodec
+ * - Codec for the low 32-bits band
+ * @param hiCodec
+ * - Codec for the high 32-bits band
+ * @param haveHiFlags
+ * - ignores the high band if true as all values would be zero
+ * @return the encoded band
+ * @throws Pack200Exception
+ */
protected byte[] encodeFlags(String name, long[] flags, BHSDCodec loCodec, BHSDCodec hiCodec,
boolean haveHiFlags) throws Pack200Exception {
if(!haveHiFlags) {
@@ -139,6 +589,9 @@
}
}
+ /**
+ * Converts a list of Integers to an int[] array
+ */
protected int[] listToArray(List integerList) {
int[] array = new int[integerList.size()];
for (int i = 0; i < array.length; i++) {
@@ -147,6 +600,9 @@
return array;
}
+ /**
+ * Converts a list of Longs to an long[] array
+ */
protected long[] longListToArray(List longList) {
long[] array = new long[longList.size()];
for (int i = 0; i < array.length; i++) {
@@ -155,6 +611,9 @@
return array;
}
+ /**
+ * Converts a list of ConstantPoolEntrys to an int[] array of their indices
+ */
protected int[] cpEntryListToArray(List list) {
int[] array = new int[list.size()];
for (int i = 0; i < array.length; i++) {
@@ -166,6 +625,10 @@
return array;
}
+ /**
+ * Converts a list of ConstantPoolEntrys or nulls to an int[] array of their
+ * indices +1 (or 0 for nulls)
+ */
protected int[] cpEntryOrNullListToArray(List theList) {
int[] array = new int[theList.size()];
for (int j = 0; j < array.length; j++) {
@@ -199,4 +662,144 @@
return flatArray;
}
+ /**
+ * BandData represents information about a band, e.g. largest value etc
+ * and is used in the heuristics that calculate whether an alternative
+ * Codec could make the encoded band smaller.
+ */
+ public class BandData {
+
+ private final int[] band;
+ private int smallest = Integer.MAX_VALUE;
+ private int largest = Integer.MIN_VALUE;
+ private int smallestDelta;
+ private int largestDelta;
+
+ private int deltaIsAscending = 0;
+ private int smallDeltaCount = 0;
+
+ private double averageAbsoluteDelta = 0;
+ private double averageAbsoluteValue = 0;
+
+ private Map distinctValues;
+
+ /**
+ * Create a new instance of BandData. The band is then analysed.
+ * @param band - the band of integers
+ */
+ public BandData(int[] band) {
+ this.band = band;
+ Integer one = new Integer(1);
+ for (int i = 0; i < band.length; i++) {
+ if(band[i] < smallest) {
+ smallest = band[i];
+ }
+ if(band[i] > largest) {
+ largest = band[i];
+ }
+ if(i != 0) {
+ int delta = band[i] - band[i - 1];
+ if(delta < smallestDelta) {
+ smallestDelta = delta;
+ }
+ if(delta > largestDelta) {
+ largestDelta = delta;
+ }
+ if(delta >= 0) {
+ deltaIsAscending++;
+ }
+ averageAbsoluteDelta += (double)Math.abs(delta)/(double)(band.length - 1);
+ if(Math.abs(delta) < 256) {
+ smallDeltaCount++;
+ }
+ } else {
+ smallestDelta = band[0];
+ largestDelta = band[0];
+ }
+ averageAbsoluteValue += (double)Math.abs(band[i])/(double)band.length;
+ if(effort > 3) { // do calculations needed to consider population codec
+ if(distinctValues == null) {
+ distinctValues = new HashMap();
+ }
+ Integer value = new Integer(band[i]);
+ Integer count = (Integer) distinctValues.get(value);
+ if(count == null) {
+ count = one;
+ } else {
+ count = new Integer(count.intValue() + 1);
+ }
+ distinctValues.put(value, count);
+ }
+ }
+ }
+
+ /**
+ * Returns true if the deltas between adjacent band elements are mainly
+ * small (heuristic)
+ */
+ public boolean mainlySmallDeltas() {
+ // Note: the value below has been tuned - please test carefully if changing it
+ return (float)smallDeltaCount/(float)band.length > 0.7F;
+ }
+
+ /**
+ * Returns true if the band is well correlated (i.e. would be suitable
+ * for a delta encoding) (heuristic)
+ */
+ public boolean wellCorrelated() {
+ // Note: the value below has been tuned - please test carefully if changing it
+ return averageAbsoluteDelta * 3.1 < averageAbsoluteValue;
+ }
+
+ /**
+ * Returns true if the band deltas are mainly positive (heuristic)
+ */
+ public boolean mainlyPositiveDeltas() {
+ // Note: the value below has been tuned - please test carefully if changing it
+ return (float)deltaIsAscending/(float)band.length > 0.95F;
+ }
+
+ /**
+ * Returns true if any band elements are negative
+ */
+ public boolean anyNegatives() {
+ return smallest < 0;
+ }
+
+ /**
+ * Returns the total number of distinct values found in the band
+ */
+ public int numDistinctValues() {
+ if(distinctValues == null) {
+ return band.length;
+ }
+ return distinctValues.size();
+ }
+
+ }
+
+ /**
+ * Results obtained by trying different Codecs to encode a band
+ */
+ public class BandAnalysisResults {
+
+ // The number of Codecs tried so far
+ private int numCodecsTried = 0;
+
+ // The number of bytes saved by using betterCodec instead of the default codec
+ private int saved = 0;
+
+ // Extra metadata to pass to the segment header (to be appended to the
+ // band_headers band)
+ private int[] extraMetadata;
+
+ // The results of encoding the band with betterCodec
+ private byte[] encodedBand;
+
+ // The best Codec found so far, or should be null if the default is the
+ // best so far
+ private Codec betterCodec;
+
+ }
+
}
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java Wed Jun 17 14:00:24 2009
@@ -26,7 +26,8 @@
import org.objectweb.asm.Label;
/**
- * Bytecode bands
+ * Bytecode bands (corresponds to the <code>bc_bands</code> set of bands in the
+ * pack200 specification)
*/
public class BcBands extends BandSet {
@@ -85,6 +86,11 @@
superClass = superName;
}
+ /**
+ * All input classes for the segment have now been read in, so this method
+ * is called so that this class can calculate/complete anything it could not
+ * do while classes were being read.
+ */
public void finaliseBands() {
bcThisField = getIndexInClass(bcThisField);
bcThisMethod = getIndexInClass(bcThisMethod);
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPClass.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPClass.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPClass.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPClass.java Wed Jun 17 14:00:24 2009
@@ -16,7 +16,9 @@
*/
package org.apache.harmony.pack200;
-
+/**
+ * Constant pool entry for a class
+ */
public class CPClass extends CPConstant implements Comparable {
private final String className;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPConstant.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPConstant.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPConstant.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPConstant.java Wed Jun 17 14:00:24 2009
@@ -16,7 +16,11 @@
*/
package org.apache.harmony.pack200;
-
-public abstract class CPConstant extends ConstantPoolEntry implements Comparable {
+/**
+ * Abstract superclass for constant pool constant entries such as numbers or
+ * Strings
+ */
+public abstract class CPConstant extends ConstantPoolEntry implements
+ Comparable {
}
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPDouble.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPDouble.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPDouble.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPDouble.java Wed Jun 17 14:00:24 2009
@@ -16,10 +16,12 @@
*/
package org.apache.harmony.pack200;
-
+/**
+ * Constant pool entry for a double.
+ */
public class CPDouble extends CPConstant {
- private double theDouble;
+ private final double theDouble;
public CPDouble(double theDouble) {
this.theDouble = theDouble;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPFloat.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPFloat.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPFloat.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPFloat.java Wed Jun 17 14:00:24 2009
@@ -16,10 +16,12 @@
*/
package org.apache.harmony.pack200;
-
+/**
+ * Constant pool entry for a float.
+ */
public class CPFloat extends CPConstant {
- private float theFloat;
+ private final float theFloat;
public CPFloat(float theFloat) {
this.theFloat = theFloat;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPInt.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPInt.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPInt.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPInt.java Wed Jun 17 14:00:24 2009
@@ -16,7 +16,9 @@
*/
package org.apache.harmony.pack200;
-
+/**
+ * Constant pool entry for an int.
+ */
public class CPInt extends CPConstant {
private final int theInt;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPLong.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPLong.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPLong.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPLong.java Wed Jun 17 14:00:24 2009
@@ -16,7 +16,9 @@
*/
package org.apache.harmony.pack200;
-
+/**
+ * Constant pool entry for a long.
+ */
public class CPLong extends CPConstant {
private final long theLong;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPMethodOrField.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPMethodOrField.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPMethodOrField.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPMethodOrField.java Wed Jun 17 14:00:24 2009
@@ -16,6 +16,9 @@
*/
package org.apache.harmony.pack200;
+/**
+ * Constant pool entry for a method or field.
+ */
public class CPMethodOrField extends ConstantPoolEntry implements Comparable {
private final CPClass className;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPNameAndType.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPNameAndType.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPNameAndType.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPNameAndType.java Wed Jun 17 14:00:24 2009
@@ -16,6 +16,9 @@
*/
package org.apache.harmony.pack200;
+/**
+ * Constant pool entry for a name and type pair.
+ */
public class CPNameAndType extends ConstantPoolEntry implements Comparable {
private final CPUTF8 name;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPSignature.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPSignature.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPSignature.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPSignature.java Wed Jun 17 14:00:24 2009
@@ -18,6 +18,9 @@
import java.util.List;
+/**
+ * Constant pool entry for a signature.
+ */
public class CPSignature extends ConstantPoolEntry implements Comparable {
private final CPUTF8 signatureForm;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPString.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPString.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPString.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPString.java Wed Jun 17 14:00:24 2009
@@ -16,7 +16,9 @@
*/
package org.apache.harmony.pack200;
-
+/**
+ * Constant pool entry for a String.
+ */
public class CPString extends CPConstant {
private final String string;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPUTF8.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPUTF8.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPUTF8.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/CPUTF8.java Wed Jun 17 14:00:24 2009
@@ -16,7 +16,9 @@
*/
package org.apache.harmony.pack200;
-
+/**
+ * Constant pool entry for a UTF8 entry, used for storing long Strings.
+ */
public class CPUTF8 extends ConstantPoolEntry implements Comparable {
private final String string;
Modified: harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java?rev=785606&r1=785605&r2=785606&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java Wed Jun 17 14:00:24 2009
@@ -19,6 +19,8 @@
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -26,11 +28,15 @@
import java.util.Map;
import java.util.Set;
+import org.apache.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
import org.apache.harmony.pack200.IcBands.IcTuple;
-import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
+/**
+ * Class bands (corresponds to the <code>class_bands</code> set of bands in the
+ * pack200 specification)
+ */
public class ClassBands extends BandSet {
private final CpBands cpBands;
@@ -77,6 +83,7 @@
private final List codeHandlerCatchPO = new ArrayList();
private final List codeHandlerClass = new ArrayList();
private final List codeFlags = new ArrayList();
+ private int[] code_attr_calls;
private final IntList codeLineNumberTableN = new IntList();
private final List codeLineNumberTableBciP = new ArrayList();
private final IntList codeLineNumberTableLine = new IntList();
@@ -103,6 +110,11 @@
private final MetadataBandGroup method_RIPA_bands;
private final MetadataBandGroup method_AD_bands;
+ private final List classAttributeBands = new ArrayList();
+ private final List methodAttributeBands = new ArrayList();
+ private final List fieldAttributeBands = new ArrayList();
+ private final List codeAttributeBands = new ArrayList();
+
private final List tempFieldFlags = new ArrayList();
private final List tempFieldDesc = new ArrayList();
private final List tempMethodFlags = new ArrayList();
@@ -114,9 +126,20 @@
private final Segment segment;
private final Map classReferencesInnerClass = new HashMap();
+ private final boolean stripDebug;
+
+ private int index = 0;
+
+ private int numMethodArgs = 0;
+ private int[] class_InnerClasses_N;
+ private CPClass[] class_InnerClasses_RC;
+ private int[] class_InnerClasses_F;
+ private List classInnerClassesOuterRCN;
+ private List classInnerClassesNameRUN;
- public ClassBands(Segment segment, int numClasses, int effort) {
+ public ClassBands(Segment segment, int numClasses, int effort, boolean stripDebug) throws IOException {
super(effort, segment.getSegmentHeader());
+ this.stripDebug = stripDebug;
this.segment = segment;
this.cpBands = segment.getCpBands();
this.attrBands = segment.getAttrBands();
@@ -143,16 +166,32 @@
method_RVPA_bands = new MetadataBandGroup("RVPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
method_RIPA_bands = new MetadataBandGroup("RIPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
method_AD_bands = new MetadataBandGroup("AD", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
- }
- private int index = 0;
+ createNewAttributeBands();
+ }
- private int numMethodArgs = 0;
- private int[] class_InnerClasses_N;
- private CPClass[] class_InnerClasses_RC;
- private int[] class_InnerClasses_F;
- private List classInnerClassesOuterRCN;
- private List classInnerClassesNameRUN;
+ private void createNewAttributeBands() throws IOException {
+ List classAttributeLayouts = attrBands.getClassAttributeLayouts();
+ for (Iterator iterator = classAttributeLayouts.iterator(); iterator.hasNext();) {
+ AttributeDefinition def = (AttributeDefinition) iterator.next();
+ classAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+ }
+ List methodAttributeLayouts = attrBands.getMethodAttributeLayouts();
+ for (Iterator iterator = methodAttributeLayouts.iterator(); iterator.hasNext();) {
+ AttributeDefinition def = (AttributeDefinition) iterator.next();
+ methodAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+ }
+ List fieldAttributeLayouts = attrBands.getFieldAttributeLayouts();
+ for (Iterator iterator = fieldAttributeLayouts.iterator(); iterator.hasNext();) {
+ AttributeDefinition def = (AttributeDefinition) iterator.next();
+ fieldAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+ }
+ List codeAttributeLayouts = attrBands.getCodeAttributeLayouts();
+ for (Iterator iterator = codeAttributeLayouts.iterator(); iterator.hasNext();) {
+ AttributeDefinition def = (AttributeDefinition) iterator.next();
+ codeAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+ }
+ }
public void addClass(int major, int flags, String className,
String signature, String superName, String[] interfaces) {
@@ -232,6 +271,11 @@
tempFieldFlags.add(new Long(flags));
}
+ /**
+ * All input classes for the segment have now been read in, so this method
+ * is called so that this class can calculate/complete anything it could not
+ * do while classes were being read.
+ */
public void finaliseBands() {
int defaultMajorVersion = segmentHeader.getDefaultMajorVersion();
for (int i = 0; i < class_flags.length; i++) {
@@ -332,6 +376,8 @@
IntList classAttrCalls = new IntList();
IntList fieldAttrCalls = new IntList();
IntList methodAttrCalls = new IntList();
+ IntList codeAttrCalls = new IntList();
+
if(class_RVA_bands.hasContent()) {
classAttrCalls.add(class_RVA_bands.numBackwardsCalls());
}
@@ -359,9 +405,61 @@
if(method_AD_bands.hasContent()) {
methodAttrCalls.add(method_AD_bands.numBackwardsCalls());
}
+
+ // Sort non-predefined attribute bands
+ Comparator comparator = new Comparator() {
+ public int compare(Object arg0, Object arg1) {
+ NewAttributeBands bands0 = (NewAttributeBands)arg0;
+ NewAttributeBands bands1 = (NewAttributeBands)arg1;
+ return bands0.getFlagIndex() - bands1.getFlagIndex();
+ }
+ };
+ Collections.sort(classAttributeBands, comparator);
+ Collections.sort(methodAttributeBands, comparator);
+ Collections.sort(fieldAttributeBands, comparator);
+ Collections.sort(codeAttributeBands, comparator);
+
+ for (Iterator iterator = classAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.isUsedAtLeastOnce()) {
+ int[] backwardsCallCounts = bands.numBackwardsCalls();
+ for (int i = 0; i < backwardsCallCounts.length; i++) {
+ classAttrCalls.add(backwardsCallCounts[i]);
+ }
+ }
+ }
+ for (Iterator iterator = methodAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.isUsedAtLeastOnce()) {
+ int[] backwardsCallCounts = bands.numBackwardsCalls();
+ for (int i = 0; i < backwardsCallCounts.length; i++) {
+ methodAttrCalls.add(backwardsCallCounts[i]);
+ }
+ }
+ }
+ for (Iterator iterator = fieldAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.isUsedAtLeastOnce()) {
+ int[] backwardsCallCounts = bands.numBackwardsCalls();
+ for (int i = 0; i < backwardsCallCounts.length; i++) {
+ fieldAttrCalls.add(backwardsCallCounts[i]);
+ }
+ }
+ }
+ for (Iterator iterator = codeAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.isUsedAtLeastOnce()) {
+ int[] backwardsCallCounts = bands.numBackwardsCalls();
+ for (int i = 0; i < backwardsCallCounts.length; i++) {
+ codeAttrCalls.add(backwardsCallCounts[i]);
+ }
+ }
+ }
+
class_attr_calls = classAttrCalls.toArray();
field_attr_calls = fieldAttrCalls.toArray();
method_attr_calls = methodAttrCalls.toArray();
+ code_attr_calls = codeAttrCalls.toArray();
}
public void pack(OutputStream out) throws IOException, Pack200Exception {
@@ -440,6 +538,10 @@
cpEntryListToArray(fieldSignature), Codec.UNSIGNED5));
field_RVA_bands.pack(out);
field_RIA_bands.pack(out);
+ for (Iterator iterator = fieldAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ bands.pack(out);
+ }
}
private void writeMethodAttributeBands(OutputStream out)
@@ -460,14 +562,25 @@
method_RVPA_bands.pack(out);
method_RIPA_bands.pack(out);
method_AD_bands.pack(out);
+ for (Iterator iterator = methodAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ bands.pack(out);
+ }
}
private void writeClassAttributeBands(OutputStream out) throws IOException,
Pack200Exception {
out.write(encodeFlags("class_flags", class_flags, Codec.UNSIGNED5,
Codec.UNSIGNED5, segmentHeader.have_class_flags_hi()));
+
+ // These bands are not needed, but could be used to reduce the size of
+ // the archive if there are enough different non-standard attributes
+ // defined that segmentHeader.have_class_flags_hi() is true. The same
+ // applies to method_attr_count, field_attr_count, code_attr_count etc.
+
// *class_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
// *class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)]
+
out.write(encodeBandInt("class_attr_calls", class_attr_calls, Codec.UNSIGNED5));
out.write(encodeBandInt("classSourceFile",
cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5));
@@ -490,6 +603,10 @@
classFileVersionMinor.toArray(), Codec.UNSIGNED5));
out.write(encodeBandInt("classFileVersionMajor",
classFileVersionMajor.toArray(), Codec.UNSIGNED5));
+ for (Iterator iterator = classAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ bands.pack(out);
+ }
}
private int[] getInts(CPClass[] cpClasses) {
@@ -527,7 +644,8 @@
// *code_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
// *code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)]
- // *code_attr_calls :UNSIGNED5 [...]
+ out.write(encodeBandInt("code_attr_calls", code_attr_calls,
+ Codec.UNSIGNED5));
out.write(encodeBandInt("code_LineNumberTable_N",
codeLineNumberTableN.toArray(), Codec.UNSIGNED5));
out.write(encodeBandInt("code_LineNumberTable_bci_P",
@@ -562,7 +680,10 @@
Codec.UNSIGNED5));
out.write(encodeBandInt("code_LocalVariableTypeTable_slot",
codeLocalVariableTypeTableSlot.toArray(), Codec.UNSIGNED5));
-
+ for (Iterator iterator = codeAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ bands.pack(out);
+ }
}
public void addMethod(int flags, String name, String desc,
@@ -690,14 +811,64 @@
.getCPNameAndType(name, desc));
}
- public void addUnknownFieldAttribute(Attribute arg0) {
- // TODO Auto-generated method stub
-
- }
-
- public void addUnknownMethodAttribute(Attribute arg0) {
- // TODO Auto-generated method stub
-
+ public void addClassAttribute(NewAttribute attribute) {
+ // TODO: backwards calls
+ String attributeName = attribute.type;
+ for (Iterator iterator = classAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.getAttributeName().equals(attributeName)) {
+ bands.addAttribute(attribute);
+ int flagIndex = bands.getFlagIndex();
+ class_flags[index] |= (1 << flagIndex);
+ return;
+ }
+ }
+ throw new RuntimeException("No suitable definition for " + attributeName);
+ }
+
+ public void addFieldAttribute(NewAttribute attribute) {
+ String attributeName = attribute.type;
+ for (Iterator iterator = fieldAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.getAttributeName().equals(attributeName)) {
+ bands.addAttribute(attribute);
+ int flagIndex = bands.getFlagIndex();
+ Long flags = (Long)tempFieldFlags.remove(tempFieldFlags.size() - 1);
+ tempFieldFlags.add(new Long(flags.longValue() | (1 << flagIndex)));
+ return;
+ }
+ }
+ throw new RuntimeException("No suitable definition for " + attributeName);
+ }
+
+ public void addMethodAttribute(NewAttribute attribute) {
+ String attributeName = attribute.type;
+ for (Iterator iterator = methodAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.getAttributeName().equals(attributeName)) {
+ bands.addAttribute(attribute);
+ int flagIndex = bands.getFlagIndex();
+ Long flags = (Long)tempMethodFlags.remove(tempMethodFlags.size() - 1);
+ tempMethodFlags.add(new Long(flags.longValue() | (1 << flagIndex)));
+ return;
+ }
+ }
+ throw new RuntimeException("No suitable definition for " + attributeName);
+ }
+
+ public void addCodeAttribute(NewAttribute attribute) {
+ String attributeName = attribute.type;
+ for (Iterator iterator = codeAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands bands = (NewAttributeBands) iterator.next();
+ if(bands.getAttributeName().equals(attributeName)) {
+ bands.addAttribute(attribute);
+ int flagIndex = bands.getFlagIndex();
+ Long flags = (Long)codeFlags.remove(codeFlags.size() - 1);
+ codeFlags.add(new Long(flags.longValue() | (1 << flagIndex)));
+ return;
+ }
+ }
+ throw new RuntimeException("No suitable definition for " + attributeName);
}
public void addMaxStack(int maxStack, int maxLocals) {
@@ -713,10 +884,10 @@
codeMaxLocals.add(maxLocals);
}
- public void addCode(boolean stripDebug) {
+ public void addCode() {
codeHandlerCount.add(0);
if(!stripDebug) {
- codeFlags.add(new Long((1 << 2))); // TODO: What if there's no debug information?
+ codeFlags.add(new Long((1 << 2)));
codeLocalVariableTableN.add(0);
}
}
@@ -743,7 +914,6 @@
}
codeLineNumberTableLine.add(line);
codeLineNumberTableBciP.add(start);
- // TODO: bci renumbering
}
public void addLocalVariable(String name, String desc, String signature,
@@ -790,6 +960,23 @@
bciRenumbering, labelsToOffsets);
renumberDoubleOffsetBci(codeHandlerStartP, codeHandlerEndPO, codeHandlerCatchPO,
bciRenumbering, labelsToOffsets);
+
+ for (Iterator iterator = classAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands newAttributeBandSet = (NewAttributeBands) iterator.next();
+ newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
+ }
+ for (Iterator iterator = methodAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands newAttributeBandSet = (NewAttributeBands) iterator.next();
+ newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
+ }
+ for (Iterator iterator = fieldAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands newAttributeBandSet = (NewAttributeBands) iterator.next();
+ newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
+ }
+ for (Iterator iterator = codeAttributeBands.iterator(); iterator.hasNext();) {
+ NewAttributeBands newAttributeBandSet = (NewAttributeBands) iterator.next();
+ newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
+ }
}
private void renumberBci(List list, IntList bciRenumbering, Map labelsToOffsets) {
@@ -946,4 +1133,136 @@
Long flag = (Long) tempMethodFlags.remove(tempMethodFlags.size() - 1);
tempMethodFlags.add(new Long(flag.longValue() | (1<<25)));
}
+
+ /**
+ * Remove all entries for the current class
+ */
+ public void removeCurrentClass() {
+ // Note - this doesn't remove any entries added to the constant pool but
+ // that shouldn't be a problem
+ if ((class_flags[index] & (1 << 17)) != 0) {
+ classSourceFile.remove(classSourceFile.size() - 1);
+ }
+ if ((class_flags[index] & (1 << 18)) != 0) {
+ classEnclosingMethodClass
+ .remove(classEnclosingMethodClass.size() - 1);
+ classEnclosingMethodDesc
+ .remove(classEnclosingMethodDesc.size() - 1);
+ }
+ if ((class_flags[index] & (1 << 19)) != 0) {
+ classSignature.remove(classSignature.size() - 1);
+ }
+ if ((class_flags[index] & (1 << 21)) != 0) {
+ class_RVA_bands.removeLatest();
+ }
+ if ((class_flags[index] & (1 << 22)) != 0) {
+ class_RIA_bands.removeLatest();
+ }
+ for (Iterator iterator = tempFieldFlags.iterator(); iterator.hasNext();) {
+ Long flagsL = (Long) iterator.next();
+ long flags = flagsL.longValue();
+ if ((flags & (1 << 19)) != 0) {
+ fieldSignature.remove(fieldSignature.size() - 1);
+ }
+ if ((flags & (1 << 17)) != 0) {
+ fieldConstantValueKQ.remove(fieldConstantValueKQ.size() - 1);
+ }
+ if ((flags & (1 << 21)) != 0) {
+ field_RVA_bands.removeLatest();
+ }
+ if ((flags & (1 << 22)) != 0) {
+ field_RIA_bands.removeLatest();
+ }
+ }
+ for (Iterator iterator = tempMethodFlags.iterator(); iterator.hasNext();) {
+ Long flagsL = (Long) iterator.next();
+ long flags = flagsL.longValue();
+ if ((flags & (1 << 19)) != 0) {
+ methodSignature.remove(methodSignature.size() - 1);
+ }
+ if ((flags & (1 << 18)) != 0) {
+ int exceptions = methodExceptionNumber
+ .remove(methodExceptionNumber.size() - 1);
+ for (int i = 0; i < exceptions; i++) {
+ methodExceptionClasses
+ .remove(methodExceptionClasses.size() - 1);
+ }
+ }
+ if ((flags & (1 << 17)) != 0) { // has code attribute
+ codeMaxLocals.remove(codeMaxLocals.size() - 1);
+ codeMaxStack.remove(codeMaxStack.size() - 1);
+ int handlers = codeHandlerCount
+ .remove(codeHandlerCount.size() - 1);
+ for (int i = 0; i < handlers; i++) {
+ int index = codeHandlerStartP.size() - 1;
+ codeHandlerStartP.remove(index);
+ codeHandlerEndPO.remove(index);
+ codeHandlerCatchPO.remove(index);
+ codeHandlerClass.remove(index);
+ }
+ if (!stripDebug) {
+ long cdeFlags = ((Long) codeFlags
+ .remove(codeFlags.size() - 1)).longValue();
+ int numLocalVariables = codeLocalVariableTableN
+ .remove(codeLocalVariableTableN.size() - 1);
+ for (int i = 0; i < numLocalVariables; i++) {
+ int location = codeLocalVariableTableBciP.size() - 1;
+ codeLocalVariableTableBciP.remove(location);
+ codeLocalVariableTableSpanO.remove(location);
+ codeLocalVariableTableNameRU.remove(location);
+ codeLocalVariableTableTypeRS.remove(location);
+ codeLocalVariableTableSlot.remove(location);
+ }
+ if ((cdeFlags & (1 << 3)) != 0) {
+ int numLocalVariablesInTypeTable = codeLocalVariableTypeTableN
+ .remove(codeLocalVariableTypeTableN.size() - 1);
+ for (int i = 0; i < numLocalVariablesInTypeTable; i++) {
+ int location = codeLocalVariableTypeTableBciP
+ .size() - 1;
+ codeLocalVariableTypeTableBciP.remove(location);
+ codeLocalVariableTypeTableSpanO.remove(location);
+ codeLocalVariableTypeTableNameRU.remove(location);
+ codeLocalVariableTypeTableTypeRS.remove(location);
+ codeLocalVariableTypeTableSlot.remove(location);
+ }
+ }
+ if ((cdeFlags & (1 << 1)) != 0) {
+ int numLineNumbers = codeLineNumberTableN
+ .remove(codeLineNumberTableN.size() - 1);
+ for (int i = 0; i < numLineNumbers; i++) {
+ int location = codeLineNumberTableBciP.size() - 1;
+ codeLineNumberTableBciP.remove(location);
+ codeLineNumberTableLine.remove(location);
+ }
+ }
+ }
+ }
+ if ((flags & (1 << 21)) != 0) {
+ method_RVA_bands.removeLatest();
+ }
+ if ((flags & (1 << 22)) != 0) {
+ method_RIA_bands.removeLatest();
+ }
+ if ((flags & (1 << 23)) != 0) {
+ method_RVPA_bands.removeLatest();
+ }
+ if ((flags & (1 << 24)) != 0) {
+ method_RIPA_bands.removeLatest();
+ }
+ if ((flags & (1 << 25)) != 0) {
+ method_AD_bands.removeLatest();
+ }
+ }
+ class_this[index] = null;
+ class_super[index] = null;
+ class_interface_count[index] = 0;
+ class_interface[index] = null;
+ major_versions[index] = 0;
+ class_flags[index] = 0;
+ tempFieldDesc.clear();
+ tempFieldFlags.clear();
+ tempMethodDesc.clear();
+ tempMethodFlags.clear();
+ index--;
+ }
}