Skip to content
Browse files

Optimize writing the class to a DataOutputStream

  • Loading branch information...
1 parent 7d4d519 commit d4df2d514c4e4ab00e4253c237eee02bbb0593ee @stuartwdouglas stuartwdouglas committed Mar 21, 2011
Showing with 293 additions and 160 deletions.
  1. +4 −3 src/main/java/org/jboss/classfilewriter/ClassField.java
  2. +10 −10 src/main/java/org/jboss/classfilewriter/ClassFile.java
  3. +7 −7 src/main/java/org/jboss/classfilewriter/ClassMethod.java
  4. +7 −5 src/main/java/org/jboss/classfilewriter/WritableEntry.java
  5. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/AnnotationAnnotationValue.java
  6. +7 −7 src/main/java/org/jboss/classfilewriter/annotations/AnnotationValue.java
  7. +12 −15 src/main/java/org/jboss/classfilewriter/annotations/AnnotationsAttribute.java
  8. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/ArrayAnnotationValue.java
  9. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/BooleanAnnotationValue.java
  10. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/ByteAnnotationValue.java
  11. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/CharAnnotationValue.java
  12. +8 −8 src/main/java/org/jboss/classfilewriter/annotations/ClassAnnotation.java
  13. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/ClassAnnotationValue.java
  14. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/DoubleAnnotationValue.java
  15. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/EnumAnnotationValue.java
  16. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/FloatAnnotationValue.java
  17. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/IntAnnotationValue.java
  18. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/LongAnnotationValue.java
  19. +14 −17 src/main/java/org/jboss/classfilewriter/annotations/ParameterAnnotationsAttribute.java
  20. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/ShortAnnotationValue.java
  21. +4 −3 src/main/java/org/jboss/classfilewriter/annotations/StringAnnotationValue.java
  22. +7 −7 src/main/java/org/jboss/classfilewriter/attributes/Attribute.java
  23. +6 −6 src/main/java/org/jboss/classfilewriter/attributes/ExceptionsAttribute.java
  24. +2 −1 src/main/java/org/jboss/classfilewriter/attributes/SignatureAttribute.java
  25. +20 −21 src/main/java/org/jboss/classfilewriter/attributes/StackMapTableAttribute.java
  26. +10 −10 src/main/java/org/jboss/classfilewriter/code/CodeAttribute.java
  27. +2 −1 src/main/java/org/jboss/classfilewriter/constpool/ConstPool.java
  28. +4 −3 src/main/java/org/jboss/classfilewriter/constpool/ConstPoolEntry.java
  29. +89 −0 src/main/java/org/jboss/classfilewriter/util/ByteArrayDataOutputStream.java
  30. +32 −0 src/main/java/org/jboss/classfilewriter/util/LazySize.java
View
7 src/main/java/org/jboss/classfilewriter/ClassField.java
@@ -30,12 +30,13 @@
import org.jboss.classfilewriter.attributes.Attribute;
import org.jboss.classfilewriter.attributes.SignatureAttribute;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* A field in a class
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ClassField implements WritableEntry {
@@ -65,7 +66,7 @@
this.attributes.add(runtimeVisibleAnnotationsAttribute);
}
- public void write(DataOutputStream stream) throws IOException {
+ public void write(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(accessFlags);
stream.writeShort(nameIndex);
stream.writeShort(descriptorIndex);
View
20 src/main/java/org/jboss/classfilewriter/ClassFile.java
@@ -44,6 +44,7 @@
import org.jboss.classfilewriter.annotations.AnnotationsAttribute;
import org.jboss.classfilewriter.attributes.Attribute;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
import org.jboss.classfilewriter.util.DescriptorUtils;
/**
@@ -195,7 +196,7 @@ public ClassMethod addConstructor(Constructor<?> method) {
return classMethod;
}
- public void write(DataOutputStream stream) throws IOException {
+ public void write(ByteArrayDataOutputStream stream) throws IOException {
// first make sure everything we need is in the const pool
short nameIndex = constPool.addClassEntry(name);
short superClassIndex = constPool.addClassEntry(superclass);
@@ -288,10 +289,9 @@ public Object run() throws Exception {
// TODO: throw illegal state exception if the class file is modified after writing
if (bytecode == null) {
try {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
- DataOutputStream out = new DataOutputStream(bytes);
+ ByteArrayDataOutputStream out = new ByteArrayDataOutputStream();
write(out);
- bytecode = bytes.toByteArray();
+ bytecode = out.getBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -305,7 +305,7 @@ public ConstPool getConstPool() {
/**
* returns the type descriptor for the class
- *
+ *
* @return
*/
public String getDescriptor() {
@@ -318,39 +318,39 @@ public AnnotationsAttribute getRuntimeVisibleAnnotationsAttribute() {
/**
* Returns the generated class name
- *
+ *
* @return The generated class name
*/
public String getName() {
return name;
}
/**
- *
+ *
* @return The generated superclass name
*/
public String getSuperclass() {
return superclass;
}
/**
- *
+ *
* @return The interfaces implemented by this class
*/
public List<String> getInterfaces() {
return Collections.unmodifiableList(interfaces);
}
/**
- *
+ *
* @return This class's fields
*/
public Set<ClassField> getFields() {
return Collections.unmodifiableSet(fields);
}
/**
- *
+ *
* @return This classes methods
*/
public Set<ClassMethod> getMethods() {
View
14 src/main/java/org/jboss/classfilewriter/ClassMethod.java
@@ -21,20 +21,20 @@
*/
package org.jboss.classfilewriter;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.List;
-
import org.jboss.classfilewriter.annotations.AnnotationsAttribute;
import org.jboss.classfilewriter.annotations.ParameterAnnotationsAttribute;
import org.jboss.classfilewriter.attributes.Attribute;
import org.jboss.classfilewriter.attributes.ExceptionsAttribute;
import org.jboss.classfilewriter.code.CodeAttribute;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
import org.jboss.classfilewriter.util.DescriptorUtils;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
public class ClassMethod implements WritableEntry {
@@ -109,7 +109,7 @@ public void addCheckedExceptions(String... exceptions) {
}
}
- public void write(DataOutputStream stream) throws IOException {
+ public void write(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(accessFlags);
stream.writeShort(nameIndex);
stream.writeShort(descriptorIndex);
View
12 src/main/java/org/jboss/classfilewriter/WritableEntry.java
@@ -21,15 +21,17 @@
*/
package org.jboss.classfilewriter;
-import java.io.DataOutputStream;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
- * a part of the class file that knows hows to write itself to a {@link DataOutputStream}
- *
+ * a part of the class file that knows hows to write itself to a {@link ByteArrayOutputStream}
+ *
* @author Stuart Douglas
- *
+ *
*/
public interface WritableEntry {
- void write(DataOutputStream stream) throws IOException;
+ void write(ByteArrayDataOutputStream stream) throws IOException;
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/AnnotationAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* Represents a nestled annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class AnnotationAnnotationValue extends AnnotationValue {
@@ -47,7 +48,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
value.write(stream);
}
View
14 src/main/java/org/jboss/classfilewriter/annotations/AnnotationValue.java
@@ -21,18 +21,18 @@
*/
package org.jboss.classfilewriter.annotations;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
import org.jboss.classfilewriter.WritableEntry;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+
+import java.io.IOException;
/**
* Represents an annotation name/value pair. This class can also represent a value an an array valued annotation instance, if
* the name is null
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public abstract class AnnotationValue implements WritableEntry {
@@ -49,15 +49,15 @@ protected AnnotationValue(ConstPool constPool, String name) {
}
}
- public void write(DataOutputStream stream) throws IOException {
+ public void write(ByteArrayDataOutputStream stream) throws IOException {
if (nameIndex != -1) {
stream.writeShort(nameIndex);
}
stream.writeByte(getTag());
writeData(stream);
}
- public abstract void writeData(DataOutputStream stream) throws IOException;
+ public abstract void writeData(ByteArrayDataOutputStream stream) throws IOException;
public String getName() {
return name;
View
27 src/main/java/org/jboss/classfilewriter/annotations/AnnotationsAttribute.java
@@ -21,21 +21,21 @@
*/
package org.jboss.classfilewriter.annotations;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
+import org.jboss.classfilewriter.attributes.Attribute;
+import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+import org.jboss.classfilewriter.util.LazySize;
+
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
-import org.jboss.classfilewriter.attributes.Attribute;
-import org.jboss.classfilewriter.constpool.ConstPool;
-
/**
* An annotations attribute
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class AnnotationsAttribute extends Attribute {
@@ -62,16 +62,13 @@ public AnnotationsAttribute(Type type, ConstPool constPool) {
@Override
- public void writeData(DataOutputStream stream) throws IOException {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
+ LazySize sizeMarker = stream.writeSize();
+ stream.writeShort(annotations.size());
for (ClassAnnotation annotation : annotations) {
- annotation.write(dos);
+ annotation.write(stream);
}
- byte[] data = bos.toByteArray();
- stream.writeInt(data.length + 2);
- stream.writeShort(annotations.size());
- stream.write(data);
+ sizeMarker.markEnd();
}
public void addAnnotation(Annotation annotation) {
View
7 src/main/java/org/jboss/classfilewriter/annotations/ArrayAnnotationValue.java
@@ -26,12 +26,13 @@
import java.util.List;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* An array annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ArrayAnnotationValue extends AnnotationValue {
@@ -48,7 +49,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(value.size());
for (AnnotationValue v : value) {
v.write(stream);
View
7 src/main/java/org/jboss/classfilewriter/annotations/BooleanAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* A boolean annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class BooleanAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/ByteAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* a byte annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ByteAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/CharAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* A char annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class CharAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
16 src/main/java/org/jboss/classfilewriter/annotations/ClassAnnotation.java
@@ -21,20 +21,20 @@
*/
package org.jboss.classfilewriter.annotations;
-import java.io.DataOutputStream;
+import org.jboss.classfilewriter.WritableEntry;
+import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.jboss.classfilewriter.WritableEntry;
-import org.jboss.classfilewriter.constpool.ConstPool;
-
/**
* A bytecode representation of a java annotation
- *
- *
+ *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ClassAnnotation implements WritableEntry {
private final String type;
@@ -49,7 +49,7 @@ public ClassAnnotation(ConstPool constPool, String type, List<AnnotationValue> a
this.annotationValues = new ArrayList<AnnotationValue>(annotationValues);
}
- public void write(DataOutputStream stream) throws IOException {
+ public void write(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(typeIndex);
stream.writeShort(annotationValues.size());
for (AnnotationValue value : annotationValues) {
View
7 src/main/java/org/jboss/classfilewriter/annotations/ClassAnnotationValue.java
@@ -25,13 +25,14 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
import org.jboss.classfilewriter.util.DescriptorUtils;
/**
* A class annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ClassAnnotationValue extends AnnotationValue {
@@ -53,7 +54,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/DoubleAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* a double annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class DoubleAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/EnumAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* An enum annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class EnumAnnotationValue extends AnnotationValue {
@@ -56,7 +57,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(typeIndex);
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/FloatAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* A float annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class FloatAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/IntAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* An int annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class IntAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/LongAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* A long annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class LongAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
31 src/main/java/org/jboss/classfilewriter/annotations/ParameterAnnotationsAttribute.java
@@ -21,23 +21,23 @@
*/
package org.jboss.classfilewriter.annotations;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
+import org.jboss.classfilewriter.attributes.Attribute;
+import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+import org.jboss.classfilewriter.util.LazySize;
+
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.jboss.classfilewriter.attributes.Attribute;
-import org.jboss.classfilewriter.constpool.ConstPool;
-
/**
* A parameter annotations attribute
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ParameterAnnotationsAttribute extends Attribute {
@@ -66,24 +66,21 @@ public ParameterAnnotationsAttribute(Type type, ConstPool constPool, int noParam
@Override
- public void writeData(DataOutputStream stream) throws IOException {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
+ LazySize sizeMarker = stream.writeSize();
+ stream.writeByte(noParameters);
for(int i = 0; i < noParameters; ++ i) {
if(!annotations.containsKey(i)) {
- dos.writeShort(0);
+ stream.writeShort(0);
} else {
List<ClassAnnotation> ans = annotations.get(i);
- dos.writeShort(ans.size());
+ stream.writeShort(ans.size());
for (ClassAnnotation annotation : ans) {
- annotation.write(dos);
+ annotation.write(stream);
}
}
}
- byte[] data = bos.toByteArray();
- stream.writeInt(data.length + 1);
- stream.writeByte(noParameters);
- stream.write(data);
+ sizeMarker.markEnd();
}
public void addAnnotation(int parameter, Annotation annotation) {
View
7 src/main/java/org/jboss/classfilewriter/annotations/ShortAnnotationValue.java
@@ -25,12 +25,13 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
/**
* short annotation value
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ShortAnnotationValue extends AnnotationValue {
@@ -50,7 +51,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
7 src/main/java/org/jboss/classfilewriter/annotations/StringAnnotationValue.java
@@ -21,10 +21,11 @@
*/
package org.jboss.classfilewriter.annotations;
-import java.io.DataOutputStream;
+import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+
import java.io.IOException;
-import org.jboss.classfilewriter.constpool.ConstPool;
/**
* A string annotation value
*/
@@ -46,7 +47,7 @@ public char getTag() {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(valueIndex);
}
View
14 src/main/java/org/jboss/classfilewriter/attributes/Attribute.java
@@ -21,17 +21,17 @@
*/
package org.jboss.classfilewriter.attributes;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
import org.jboss.classfilewriter.WritableEntry;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+
+import java.io.IOException;
/**
* Represents an attribute in a class file
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public abstract class Attribute implements WritableEntry {
@@ -45,12 +45,12 @@ public Attribute(String name, final ConstPool constPool) {
this.constPool = constPool;
}
- public void write(DataOutputStream stream) throws IOException {
+ public void write(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(nameIndex);
writeData(stream);
}
- public abstract void writeData(DataOutputStream stream) throws IOException;
+ public abstract void writeData(ByteArrayDataOutputStream stream) throws IOException;
public String getName() {
return name;
View
12 src/main/java/org/jboss/classfilewriter/attributes/ExceptionsAttribute.java
@@ -21,18 +21,18 @@
*/
package org.jboss.classfilewriter.attributes;
-import java.io.DataOutputStream;
+import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.jboss.classfilewriter.constpool.ConstPool;
-
/**
* The exceptions attribute, stores the checked exceptions a method is declared to throw
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class ExceptionsAttribute extends Attribute {
@@ -55,7 +55,7 @@ public void addExceptionClass(String exception) {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeInt(2 + exceptionClassIndexes.size() * 2);
stream.writeShort(exceptionClassIndexes.size());
for (short i : exceptionClassIndexes) {
View
3 src/main/java/org/jboss/classfilewriter/attributes/SignatureAttribute.java
@@ -25,6 +25,7 @@
import java.io.IOException;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
public class SignatureAttribute extends Attribute {
@@ -41,7 +42,7 @@ public SignatureAttribute(final ConstPool constPool, String signature) {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
stream.writeInt(2); // data length
stream.writeShort(signatureIndex);
}
View
41 src/main/java/org/jboss/classfilewriter/attributes/StackMapTableAttribute.java
@@ -21,28 +21,29 @@
*/
package org.jboss.classfilewriter.attributes;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jboss.classfilewriter.ClassMethod;
import org.jboss.classfilewriter.code.CodeAttribute;
import org.jboss.classfilewriter.code.StackEntry;
import org.jboss.classfilewriter.code.StackEntryType;
import org.jboss.classfilewriter.code.StackFrame;
import org.jboss.classfilewriter.code.StackFrameType;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+import org.jboss.classfilewriter.util.LazySize;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
/**
* A JDK 6 StackMap sttribute.
- *
+ *
*TODO: this will currently fall over if the code length, max locals or max stack is above 65535
- *
+ *
* @author Stuart Douglas
- *
+ *
*/
public class StackMapTableAttribute extends Attribute {
@@ -60,33 +61,31 @@ public StackMapTableAttribute(ClassMethod classMethod, ConstPool constPool) {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
// as we don't know the size yet we write everything to a byte stream first
// TODO: make this better
final CodeAttribute ca = method.getCodeAttribute();
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- DataOutputStream dstream = new DataOutputStream(bout);
// now we need to write the stack frames.
// for now we are going to write all frames as full frames
// TODO: optimise the frame creation
+
+ // write to dstream
+ LazySize size = stream.writeSize();
+ stream.writeShort(ca.getStackFrames().size());
int lastPos = -1;
for (Entry<Integer, StackFrame> entry : method.getCodeAttribute().getStackFrames().entrySet()) {
int offset = entry.getKey() - lastPos - 1;
lastPos = entry.getKey();
StackFrame frame = entry.getValue();
if (frame.getType() == StackFrameType.SAME_FRAME || frame.getType() == StackFrameType.SAME_FRAME_EXTENDED) {
- writeSameFrame(dstream, offset, lastPos, frame);
+ writeSameFrame(stream, offset, lastPos, frame);
} else if (frame.getType() == StackFrameType.SAME_LOCALS_1_STACK && offset < (127 - 64)) {
- writeSameLocals1Stack(dstream, offset, lastPos, frame);
+ writeSameLocals1Stack(stream, offset, lastPos, frame);
} else {
- writeFullFrame(dstream, offset, lastPos, entry.getValue());
+ writeFullFrame(stream, offset, lastPos, entry.getValue());
}
}
-
- // write to dstream
- stream.writeInt(bout.size() + 2);
- stream.writeShort(ca.getStackFrames().size());
- stream.write(bout.toByteArray());
+ size.markEnd();
}
private void writeSameLocals1Stack(DataOutputStream dstream, int offset, int lastPos, StackFrame frame) throws IOException {
View
20 src/main/java/org/jboss/classfilewriter/code/CodeAttribute.java
@@ -39,7 +39,9 @@
import org.jboss.classfilewriter.attributes.Attribute;
import org.jboss.classfilewriter.attributes.StackMapTableAttribute;
import org.jboss.classfilewriter.constpool.ConstPool;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
import org.jboss.classfilewriter.util.DescriptorUtils;
+import org.jboss.classfilewriter.util.LazySize;
public class CodeAttribute extends Attribute {
@@ -103,7 +105,7 @@ public CodeAttribute(ClassMethod method, ConstPool constPool) {
}
@Override
- public void writeData(DataOutputStream stream) throws IOException {
+ public void writeData(ByteArrayDataOutputStream stream) throws IOException {
if (stackMapAttributeValid) {
// add the stack map table
@@ -118,13 +120,8 @@ public void writeData(DataOutputStream stream) throws IOException {
for (Entry<Integer, Integer> e : jumpLocations.entrySet()) {
overwriteShort(bytecode, e.getKey(), e.getValue());
}
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- for (Attribute attribute : attributes) {
- attribute.write(dos);
- }
- stream.writeInt(finalDataBytes.size() + 12 + bos.size() + (exceptionTable.size() * 8)); // attribute length
+ LazySize size = stream.writeSize();
stream.writeShort(maxStackDepth);
stream.writeShort(maxLocals);
stream.writeInt(bytecode.length);
@@ -137,7 +134,10 @@ public void writeData(DataOutputStream stream) throws IOException {
stream.writeShort(exception.getExceptionIndex());
}
stream.writeShort(attributes.size()); // attributes count
- stream.write(bos.toByteArray());
+ for (Attribute attribute : attributes) {
+ attribute.write(stream);
+ }
+ size.markEnd();;
}
// -------------------------------------------
@@ -1572,7 +1572,7 @@ public void lneg() {
/**
* Generates the apprpriate load instruction for the given type
- *
+ *
* @param type The type of variable
* @param no local variable number
*/
@@ -1582,7 +1582,7 @@ public void load(Class<?> type, int no) {
/**
* Generates the apprpriate load instruction for the given type
- *
+ *
* @param descriptor The descriptor of the variable
* @param no local variable number
*/
View
3 src/main/java/org/jboss/classfilewriter/constpool/ConstPool.java
@@ -29,6 +29,7 @@
import java.util.Map.Entry;
import org.jboss.classfilewriter.WritableEntry;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
public class ConstPool implements WritableEntry {
@@ -201,7 +202,7 @@ public short addInterfaceMethodEntry(String className, String methodName, String
return index;
}
- public void write(DataOutputStream stream) throws IOException {
+ public void write(ByteArrayDataOutputStream stream) throws IOException {
stream.writeShort(constPoolSize);
for (Entry<Short, ConstPoolEntry> entry : entries.entrySet()) {
entry.getValue().write(stream);
View
7 src/main/java/org/jboss/classfilewriter/constpool/ConstPoolEntry.java
@@ -21,15 +21,16 @@
*/
package org.jboss.classfilewriter.constpool;
+import org.jboss.classfilewriter.WritableEntry;
+import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
+
import java.io.DataOutputStream;
import java.io.IOException;
-import org.jboss.classfilewriter.WritableEntry;
-
public abstract class ConstPoolEntry implements WritableEntry {
- public final void write(DataOutputStream stream) throws IOException {
+ public final void write(ByteArrayDataOutputStream stream) throws IOException {
stream.writeByte(getType().getTag());
writeData(stream);
}
View
89 src/main/java/org/jboss/classfilewriter/util/ByteArrayDataOutputStream.java
@@ -0,0 +1,89 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.classfilewriter.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DataOutputStream sub class that allows for the lazy writing of length values.
+ * <p/>
+ * These length values are inserted into the bytes when then final bytes are read.
+ * @author Stuart Douglas
+ */
+public class ByteArrayDataOutputStream extends DataOutputStream {
+
+ private final ByteArrayOutputStream bytes;
+ private final List<LazySizeImpl> sizes = new ArrayList<LazySizeImpl>();
+
+ public ByteArrayDataOutputStream(ByteArrayOutputStream bytes) {
+ super(bytes);
+ this.bytes = bytes;
+ }
+
+ public ByteArrayDataOutputStream() {
+ this(new ByteArrayOutputStream());
+ }
+
+ public LazySize writeSize() throws IOException {
+ LazySizeImpl sv = new LazySizeImpl(this.written);
+ sizes.add(sv);
+ writeInt(0);
+ return sv;
+ }
+
+ public byte[] getBytes() {
+ byte[] data = bytes.toByteArray();
+ for (final LazySizeImpl i : sizes) {
+ overwriteInt(data, i.position, i.value);
+ }
+ return data;
+ }
+
+ /**
+ * overwrites a 32 bit value in the already written bytecode data
+ */
+ private void overwriteInt(byte[] bytecode, int offset, int value) {
+ bytecode[offset] = (byte) (value >> 24);
+ bytecode[offset + 1] = (byte) (value >> 16);
+ bytecode[offset + 2] = (byte) (value >> 8);
+ bytecode[offset + 3] = (byte) (value);
+ }
+
+ private class LazySizeImpl implements LazySize {
+ private final int position;
+ private int value;
+
+ public LazySizeImpl(int position) {
+ this.position = position;
+ }
+
+ @Override
+ public void markEnd() {
+ value = written - position - 4;
+ }
+ }
+
+}
View
32 src/main/java/org/jboss/classfilewriter/util/LazySize.java
@@ -0,0 +1,32 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.classfilewriter.util;
+
+/**
+ * Represents a place holder for a size value in a byte array that can be written to later.
+ *
+ * @author Stuart Douglas
+ */
+public interface LazySize {
+
+ void markEnd();
+}

0 comments on commit d4df2d5

Please sign in to comment.
Something went wrong with that request. Please try again.