From 1b5a7c430821ff67ebe5014d7c9481dde3009c50 Mon Sep 17 00:00:00 2001 From: chiba Date: Sat, 8 May 2010 16:15:56 +0000 Subject: [PATCH] added a simple ASM-like API. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@542 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- src/main/javassist/bytecode/ByteStream.java | 193 +++++ .../javassist/bytecode/ClassFileWriter.java | 730 ++++++++++++++++++ src/main/javassist/tools/Dump.java | 4 +- 3 files changed, 925 insertions(+), 2 deletions(-) create mode 100644 src/main/javassist/bytecode/ByteStream.java create mode 100644 src/main/javassist/bytecode/ClassFileWriter.java diff --git a/src/main/javassist/bytecode/ByteStream.java b/src/main/javassist/bytecode/ByteStream.java new file mode 100644 index 00000000..82b30c9c --- /dev/null +++ b/src/main/javassist/bytecode/ByteStream.java @@ -0,0 +1,193 @@ +/* + * Javassist, a Java-bytecode translator toolkit. + * Copyright (C) 1999-2010 Shigeru Chiba. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. Alternatively, the contents of this file may be used under + * the terms of the GNU Lesser General Public License Version 2.1 or later. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + */ + +package javassist.bytecode; + +import java.io.OutputStream; +import java.io.IOException; + +final class ByteStream extends OutputStream { + private byte[] buf; + private int count; + + public ByteStream() { this(32); } + + public ByteStream(int size) { + buf = new byte[size]; + count = 0; + } + + public int getPos() { return count; } + public int size() { return count; } + + public void writeBlank(int len) { + enlarge(len); + count += len; + } + + public void write(byte[] data) { + write(data, 0, data.length); + } + + public void write(byte[] data, int off, int len) { + enlarge(len); + System.arraycopy(data, off, buf, count, len); + count += len; + } + + public void write(int b) { + enlarge(1); + int oldCount = count; + buf[oldCount] = (byte)b; + count = oldCount + 1; + } + + public void writeShort(int s) { + enlarge(2); + int oldCount = count; + buf[oldCount] = (byte)(s >>> 8); + buf[oldCount + 1] = (byte)s; + count = oldCount + 2; + } + + public void writeInt(int i) { + enlarge(4); + int oldCount = count; + buf[oldCount] = (byte)(i >>> 24); + buf[oldCount + 1] = (byte)(i >>> 16); + buf[oldCount + 2] = (byte)(i >>> 8); + buf[oldCount + 3] = (byte)i; + count = oldCount + 4; + } + + public void writeLong(long i) { + enlarge(8); + int oldCount = count; + buf[oldCount] = (byte)(i >>> 56); + buf[oldCount + 1] = (byte)(i >>> 48); + buf[oldCount + 2] = (byte)(i >>> 40); + buf[oldCount + 3] = (byte)(i >>> 32); + buf[oldCount + 4] = (byte)(i >>> 24); + buf[oldCount + 5] = (byte)(i >>> 16); + buf[oldCount + 6] = (byte)(i >>> 8); + buf[oldCount + 7] = (byte)i; + count = oldCount + 8; + } + + public void writeFloat(float v) { + writeInt(Float.floatToIntBits(v)); + } + + public void writeDouble(double v) { + writeLong(Double.doubleToLongBits(v)); + } + + public void writeUTF(String s) { + int sLen = s.length(); + int pos = count; + enlarge(sLen + 2); + + byte[] buffer = buf; + buffer[pos++] = (byte)(sLen >>> 8); + buffer[pos++] = (byte)sLen; + for (int i = 0; i < sLen; ++i) { + char c = s.charAt(i); + if (0x01 <= c && c <= 0x7f) + buffer[pos++] = (byte)c; + else { + writeUTF2(s, sLen, i); + return; + } + } + + count = pos; + } + + private void writeUTF2(String s, int sLen, int offset) { + int size = sLen; + for (int i = offset; i < sLen; i++) { + int c = s.charAt(i); + if (c > 0x7ff) + size += 2; // 3 bytes code + else if (c == 0 || c > 0x7f) + ++size; // 2 bytes code + } + + if (size > 65535) + throw new RuntimeException( + "encoded string too long: " + sLen + size + " bytes"); + + enlarge(size + 2); + int pos = count; + byte[] buffer = buf; + buffer[pos] = (byte)(size >>> 8); + buffer[pos + 1] = (byte)size; + pos += 2 + offset; + for (int j = offset; j < sLen; ++j) { + int c = s.charAt(j); + if (0x01 <= c && c <= 0x7f) + buffer[pos++] = (byte) c; + else if (c > 0x07ff) { + buffer[pos] = (byte)(0xe0 | ((c >> 12) & 0x0f)); + buffer[pos + 1] = (byte)(0x80 | ((c >> 6) & 0x3f)); + buffer[pos + 2] = (byte)(0x80 | (c & 0x3f)); + pos += 3; + } + else { + buffer[pos] = (byte)(0xc0 | ((c >> 6) & 0x1f)); + buffer[pos + 1] = (byte)(0x80 | (c & 0x3f)); + pos += 2; + } + } + + count = pos; + } + + public void write(int pos, int value) { + buf[pos] = (byte)value; + } + + public void writeShort(int pos, int value) { + buf[pos] = (byte)(value >>> 8); + buf[pos + 1] = (byte)value; + } + + public void writeInt(int pos, int value) { + buf[pos] = (byte)(value >>> 24); + buf[pos + 1] = (byte)(value >>> 16); + buf[pos + 2] = (byte)(value >>> 8); + buf[pos + 3] = (byte)value; + } + + public byte[] toByteArray() { + byte[] buf2 = new byte[count]; + System.arraycopy(buf, 0, buf2, 0, count); + return buf2; + } + + public void writeTo(OutputStream out) throws IOException { + out.write(buf, 0, count); + } + + public void enlarge(int delta) { + int newCount = count + delta; + if (newCount > buf.length) { + int newLen = buf.length << 1; + byte[] newBuf = new byte[newLen > newCount ? newLen : newCount]; + System.arraycopy(buf, 0, newBuf, 0, count); + buf = newBuf; + } + } +} diff --git a/src/main/javassist/bytecode/ClassFileWriter.java b/src/main/javassist/bytecode/ClassFileWriter.java new file mode 100644 index 00000000..012f495b --- /dev/null +++ b/src/main/javassist/bytecode/ClassFileWriter.java @@ -0,0 +1,730 @@ +/* + * Javassist, a Java-bytecode translator toolkit. + * Copyright (C) 1999-2010 Shigeru Chiba. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. Alternatively, the contents of this file may be used under + * the terms of the GNU Lesser General Public License Version 2.1 or later. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + */ + +package javassist.bytecode; + +import java.io.OutputStream; +import java.io.DataOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * A quick class-file writer. This is useful when a generated + * class file is simple and the code generation should be fast. + * + *

Example: + * + *

+ * ClassFileWriter cfw = new ClassFileWriter(ClassFile.JAVA_4, 0);
+ * ConstPoolWriter cpw = cfw.getConstPool();
+ *
+ * FieldWriter fw = cfw.getFieldWriter();
+ * fw.add(AccessFlag.PUBLIC, "value", "I", null);
+ * fw.add(AccessFlag.PUBLIC, "value2", "J", null);
+ *
+ * int thisClass = cpw.addClassInfo("sample/Test");
+ * int superClass = cpw.addClassInfo("java/lang/Object");
+ *
+ * MethodWriter mw = cfw.getMethodWriter();
+ *
+ * mw.begin(AccessFlag.PUBLIC, MethodInfo.nameInit, "()V", null, null);
+ * mw.add(Opcode.ALOAD_0);
+ * mw.add(Opcode.INVOKESPECIAL);
+ * int signature = cpw.addNameAndTypeInfo(MethodInfo.nameInit, "()V");
+ * mw.add16(cpw.addMethodrefInfo(superClass, signature));
+ * mw.add(Opcode.RETURN);
+ * mw.codeEnd(1, 1);
+ * mw.end(null, null);
+ *
+ * mw.begin(AccessFlag.PUBLIC, "one", "()I", null, null);
+ * mw.add(Opcode.ICONST_1);
+ * mw.add(Opcode.IRETURN);
+ * mw.codeEnd(1, 1);
+ * mw.end(null, null);
+ *
+ * byte[] classfile = cfw.end(AccessFlag.PUBLIC, thisClass, superClass,
+ *                            null, null);
+ * 
+ * + *

The code above generates the following class: + * + *

+ * package sample;
+ * public class Test {
+ *     public int value;
+ *     public long value2;
+ *     public Test() { super(); }
+ *     public one() { return 1; }
+ * }
+ * 
+ * + * @since 3.13 + */ +public class ClassFileWriter { + private ByteStream output; + private ConstPoolWriter constPool; + private FieldWriter fields; + private MethodWriter methods; + int thisClass, superClass; + + /** + * Constructs a class file writer. + * + * @param major the major version ({@link ClassFile#JAVA_4}, {@link ClassFile#JAVA_5}, ...). + * @param minor the minor version (0 for JDK 1.3 and later). + */ + public ClassFileWriter(int major, int minor) { + output = new ByteStream(512); + output.writeInt(0xCAFEBABE); // magic + output.writeShort(minor); + output.writeShort(major); + constPool = new ConstPoolWriter(output); + fields = new FieldWriter(constPool); + methods = new MethodWriter(constPool); + + } + + /** + * Returns a constant pool. + */ + public ConstPoolWriter getConstPool() { return constPool; } + + /** + * Returns a filed writer. + */ + public FieldWriter getFieldWriter() { return fields; } + + /** + * Returns a method writer. + */ + public MethodWriter getMethodWriter() { return methods; } + + /** + * Ends writing and returns the contents of the class file. + * + * @param accessFlags access flags. + * @param thisClass this class. an index indicating its CONSTANT_Class_info. + * @param superClass super class. an index indicating its CONSTANT_Class_info. + * @param interfaces implemented interfaces. + * index numbers indicating their ClassInfo. + * It may be null. + * @param aw attributes of the class file. May be null. + * + * @see AccessFlag + */ + public byte[] end(int accessFlags, int thisClass, int superClass, + int[] interfaces, AttributeWriter aw) { + constPool.end(); + output.writeShort(accessFlags); + output.writeShort(thisClass); + output.writeShort(superClass); + if (interfaces == null) + output.writeShort(0); + else { + int n = interfaces.length; + output.writeShort(n); + for (int i = 0; i < n; i++) + output.writeShort(interfaces[i]); + } + + output.enlarge(fields.dataSize() + methods.dataSize() + 6); + try { + output.writeShort(fields.size()); + fields.write(output); + + output.writeShort(methods.size()); + methods.write(output); + } + catch (IOException e) {} + + writeAttribute(output, aw, 0); + return output.toByteArray(); + } + + /** + * Ends writing and writes the contents of the class file into the + * given output stream. + * + * @param accessFlags access flags. + * @param thisClass this class. an index indicating its CONSTANT_Class_info. + * @param superClass super class. an index indicating its CONSTANT_Class_info. + * @param interfaces implemented interfaces. + * index numbers indicating their CONSTATNT_Class_info. + * It may be null. + * @param aw attributes of the class file. May be null. + * + * @see AccessFlag + */ + public void end(DataOutputStream out, + int accessFlags, int thisClass, int superClass, + int[] interfaces, AttributeWriter aw) + throws IOException + { + constPool.end(); + output.writeTo(out); + out.writeShort(accessFlags); + out.writeShort(thisClass); + out.writeShort(superClass); + if (interfaces == null) + out.writeShort(0); + else { + int n = interfaces.length; + out.writeShort(n); + for (int i = 0; i < n; i++) + out.writeShort(interfaces[i]); + } + + out.writeShort(fields.size()); + fields.write(out); + + out.writeShort(methods.size()); + methods.write(out); + if (aw == null) + out.writeShort(0); + else { + out.writeShort(aw.size()); + aw.write(out); + } + } + + /** + * This writes attributes. + * + *

For example, the following object writes a synthetic attribute: + * + *

+     * ConstPoolWriter cpw = ...;
+     * final int tag = cpw.addUtf8Info("Synthetic");
+     * AttributeWriter aw = new AttributeWriter() {
+     *     public int size() {
+     *         return 1;
+     *     }
+     *     public void write(DataOutputStream out) throws java.io.IOException {
+     *         out.writeShort(tag);
+     *         out.writeInt(0);
+     *     }
+     * };
+     * 
+ */ + public static interface AttributeWriter { + /** + * Returns the number of attributes that this writer will + * write. + */ + public int size(); + + /** + * Writes all the contents of the attributes. The binary representation + * of the contents is an array of attribute_info. + */ + public void write(DataOutputStream out) throws IOException; + } + + static void writeAttribute(ByteStream bs, AttributeWriter aw, int attrCount) { + if (aw == null) { + bs.writeShort(attrCount); + return; + } + + bs.writeShort(aw.size() + attrCount); + DataOutputStream dos = new DataOutputStream(bs); + try { + aw.write(dos); + dos.flush(); + } + catch (IOException e) {} + } + + /** + * Field. + */ + public static final class FieldWriter { + protected ByteStream output; + protected ConstPoolWriter constPool; + private int fieldCount; + + FieldWriter(ConstPoolWriter cp) { + output = new ByteStream(128); + constPool = cp; + fieldCount = 0; + } + + /** + * Adds a new field. + * + * @param accessFlags access flags. + * @param name the field name. + * @param descriptor the field type. + * @param aw the attributes of the field. may be null. + * @see AccessFlag + */ + public void add(int accessFlags, String name, String descriptor, AttributeWriter aw) { + int nameIndex = constPool.addUtf8Info(name); + int descIndex = constPool.addUtf8Info(descriptor); + add(accessFlags, nameIndex, descIndex, aw); + } + + /** + * Adds a new field. + * + * @param accessFlags access flags. + * @param name the field name. an index indicating its CONSTANT_Utf8_info. + * @param descriptor the field type. an index indicating its CONSTANT_Utf8_info. + * @param aw the attributes of the field. may be null. + * @see AccessFlag + */ + public void add(int accessFlags, int name, int descriptor, AttributeWriter aw) { + ++fieldCount; + output.writeShort(accessFlags); + output.writeShort(name); + output.writeShort(descriptor); + writeAttribute(output, aw, 0); + } + + int size() { return fieldCount; } + + int dataSize() { return output.size(); } + + /** + * Writes the added fields. + */ + void write(OutputStream out) throws IOException { + output.writeTo(out); + } + } + + /** + * Method. + */ + public static final class MethodWriter { + protected ByteStream output; + protected ConstPoolWriter constPool; + private int methodCount; + protected int codeIndex; + protected int throwsIndex; + protected int stackIndex; + + private int startPos; + private boolean isAbstract; + private int catchPos; + private int catchCount; + + MethodWriter(ConstPoolWriter cp) { + output = new ByteStream(256); + constPool = cp; + methodCount = 0; + codeIndex = 0; + throwsIndex = 0; + stackIndex = 0; + } + + /** + * Starts Adding a new method. + * + * @param accessFlags access flags. + * @param name the method name. + * @param descriptor the method signature. + * @param exceptions throws clause. It may be null. + * The class names must be the JVM-internal + * representations like java/lang/Exception. + * @param aw attributes to the Method_info. + */ + public void begin(int accessFlags, String name, String descriptor, + String[] exceptions, AttributeWriter aw) { + int nameIndex = constPool.addUtf8Info(name); + int descIndex = constPool.addUtf8Info(descriptor); + int[] intfs; + if (exceptions == null) + intfs = null; + else + intfs = constPool.addClassInfo(exceptions); + + begin(accessFlags, nameIndex, descIndex, intfs, aw); + } + + /** + * Starts adding a new method. + * + * @param accessFlags access flags. + * @param name the method name. an index indicating its CONSTANT_Utf8_info. + * @param descriptor the field type. an index indicating its CONSTANT_Utf8_info. + * @param exceptions throws clause. indexes indicating CONSTANT_Class_infos. + * It may be null. + * @param aw attributes to the Method_info. + */ + public void begin(int accessFlags, int name, int descriptor, int[] exceptions, AttributeWriter aw) { + ++methodCount; + output.writeShort(accessFlags); + output.writeShort(name); + output.writeShort(descriptor); + isAbstract = (accessFlags & AccessFlag.ABSTRACT) != 0; + + int attrCount = isAbstract ? 0 : 1; + if (exceptions != null) + ++attrCount; + + writeAttribute(output, aw, attrCount); + + if (exceptions != null) + writeThrows(exceptions); + + if (!isAbstract) { + if (codeIndex == 0) + codeIndex = constPool.addUtf8Info(CodeAttribute.tag); + + startPos = output.getPos(); + output.writeShort(codeIndex); + output.writeBlank(12); // attribute_length, maxStack, maxLocals, code_lenth + } + + catchPos = -1; + catchCount = 0; + } + + private void writeThrows(int[] exceptions) { + if (throwsIndex == 0) + throwsIndex = constPool.addUtf8Info(ExceptionsAttribute.tag); + + output.writeShort(throwsIndex); + output.writeInt(exceptions.length * 2 + 2); + output.writeShort(exceptions.length); + for (int i = 0; i < exceptions.length; i++) + output.writeShort(exceptions[i]); + } + + /** + * Appends an 8bit value of bytecode. + * + * @see Opcode + */ + public void add(int b) { + output.write(b); + } + + /** + * Appends a 16bit value of bytecode. + */ + public void add16(int b) { + output.writeShort(b); + } + + /** + * Appends a 32bit value of bytecode. + */ + public void add32(int b) { + output.writeInt(b); + } + + /** + * Appends a invokevirtual, inovkespecial, or invokestatic bytecode. + * + * @see Opcode + */ + public void addInvoke(int opcode, String targetClass, String methodName, + String descriptor) { + int target = constPool.addClassInfo(targetClass); + int nt = constPool.addNameAndTypeInfo(methodName, descriptor); + int method = constPool.addMethodrefInfo(target, nt); + add(opcode); + add16(method); + } + + /** + * Ends appending bytecode. + */ + public void codeEnd(int maxStack, int maxLocals) { + if (!isAbstract) { + output.writeShort(startPos + 6, maxStack); + output.writeShort(startPos + 8, maxLocals); + output.writeInt(startPos + 10, output.getPos() - startPos - 14); // code_length + catchPos = output.getPos(); + catchCount = 0; + output.writeShort(0); // number of catch clauses + } + } + + /** + * Appends an exception_table entry to the + * Code_attribute. This method is available + * only after the codeEnd method is called. + * + * @param catchType an index indicating a CONSTANT_Class_info. + */ + public void addCatch(int startPc, int endPc, int handlerPc, int catchType) { + ++catchCount; + output.writeShort(startPc); + output.writeShort(endPc); + output.writeShort(handlerPc); + output.writeShort(catchType); + } + + /** + * Ends adding a new method. The add method must be + * called before the end method is called. + * + * @param smap a stack map table. may be null. + * @param aw attributes to the Code_attribute. + * may be null. + */ + public void end(StackMapTable.Writer smap, AttributeWriter aw) { + if (isAbstract) + return; + + // exception_table_length + output.writeShort(catchPos, catchCount); + + int attrCount = smap == null ? 0 : 1; + writeAttribute(output, aw, attrCount); + + if (smap != null) { + if (stackIndex == 0) + stackIndex = constPool.addUtf8Info(StackMapTable.tag); + + output.writeShort(stackIndex); + byte[] data = smap.toByteArray(); + output.writeInt(data.length); + output.write(data); + } + + // Code attribute_length + output.writeInt(startPos + 2, output.getPos() - startPos - 6); + } + + int size() { return methodCount; } + + int dataSize() { return output.size(); } + + /** + * Writes the added methods. + */ + void write(OutputStream out) throws IOException { + output.writeTo(out); + } + } + + /** + * Constant Pool. + */ + public static final class ConstPoolWriter { + ByteStream output; + protected int startPos; + protected int num; + + ConstPoolWriter(ByteStream out) { + output = out; + startPos = out.getPos(); + num = 1; + output.writeShort(1); // number of entries + } + + /** + * Makes CONSTANT_Class_info objects for each class name. + * + * @return an array of indexes indicating CONSTANT_Class_infos. + */ + public int[] addClassInfo(String[] classNames) { + int n = classNames.length; + int[] result = new int[n]; + for (int i = 0; i < n; i++) + result[i] = addClassInfo(classNames[i]); + + return result; + } + + /** + * Adds a new CONSTANT_Class_info structure. + * + *

This also adds a CONSTANT_Utf8_info structure + * for storing the class name. + * + * @param jvmname the JVM-internal representation of a class name. + * e.g. java/lang/Object. + * @return the index of the added entry. + */ + public int addClassInfo(String jvmname) { + int utf8 = addUtf8Info(jvmname); + output.write(ClassInfo.tag); + output.writeShort(utf8); + return num++; + } + + /** + * Adds a new CONSTANT_Class_info structure. + * + * @param name name_index + * @return the index of the added entry. + */ + public int addClassInfo(int name) { + output.write(ClassInfo.tag); + output.writeShort(name); + return num++; + } + + /** + * Adds a new CONSTANT_NameAndType_info structure. + * + * @param name name_index + * @param type descriptor_index + * @return the index of the added entry. + */ + public int addNameAndTypeInfo(String name, String type) { + return addNameAndTypeInfo(addUtf8Info(name), addUtf8Info(type)); + } + + /** + * Adds a new CONSTANT_NameAndType_info structure. + * + * @param name name_index + * @param type descriptor_index + * @return the index of the added entry. + */ + public int addNameAndTypeInfo(int name, int type) { + output.write(NameAndTypeInfo.tag); + output.writeShort(name); + output.writeShort(type); + return num++; + } + + /** + * Adds a new CONSTANT_Fieldref_info structure. + * + * @param classInfo class_index + * @param nameAndTypeInfo name_and_type_index. + * @return the index of the added entry. + */ + public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) { + output.write(FieldrefInfo.tag); + output.writeShort(classInfo); + output.writeShort(nameAndTypeInfo); + return num++; + } + + /** + * Adds a new CONSTANT_Methodref_info structure. + * + * @param classInfo class_index + * @param nameAndTypeInfo name_and_type_index. + * @return the index of the added entry. + */ + public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) { + output.write(MethodrefInfo.tag); + output.writeShort(classInfo); + output.writeShort(nameAndTypeInfo); + return num++; + } + + /** + * Adds a new CONSTANT_InterfaceMethodref_info + * structure. + * + * @param classInfo class_index + * @param nameAndTypeInfo name_and_type_index. + * @return the index of the added entry. + */ + public int addInterfaceMethodrefInfo(int classInfo, + int nameAndTypeInfo) { + output.write(InterfaceMethodrefInfo.tag); + output.writeShort(classInfo); + output.writeShort(nameAndTypeInfo); + return num++; + } + + /** + * Adds a new CONSTANT_String_info + * structure. + * + *

This also adds a new CONSTANT_Utf8_info + * structure. + * + * @return the index of the added entry. + */ + public int addStringInfo(String str) { + output.write(StringInfo.tag); + output.writeShort(addUtf8Info(str)); + return num++; + } + + /** + * Adds a new CONSTANT_Integer_info + * structure. + * + * @return the index of the added entry. + */ + public int addIntegerInfo(int i) { + output.write(IntegerInfo.tag); + output.writeInt(i); + return num++; + } + + /** + * Adds a new CONSTANT_Float_info + * structure. + * + * @return the index of the added entry. + */ + public int addFloatInfo(float f) { + output.write(FloatInfo.tag); + output.writeFloat(f); + return num++; + } + + /** + * Adds a new CONSTANT_Long_info + * structure. + * + * @return the index of the added entry. + */ + public int addLongInfo(long l) { + output.write(LongInfo.tag); + output.writeLong(l); + int n = num; + num += 2; + return n; + } + + /** + * Adds a new CONSTANT_Double_info + * structure. + * + * @return the index of the added entry. + */ + public int addDoubleInfo(double d) { + output.write(DoubleInfo.tag); + output.writeDouble(d); + int n = num; + num += 2; + return n; + } + + /** + * Adds a new CONSTANT_Utf8_info + * structure. + * + * @return the index of the added entry. + */ + public int addUtf8Info(String utf8) { + output.write(Utf8Info.tag); + output.writeUTF(utf8); + return num++; + } + + /** + * Writes the contents of this class pool. + */ + void end() { + output.writeShort(startPos, num); + } + } +} diff --git a/src/main/javassist/tools/Dump.java b/src/main/javassist/tools/Dump.java index 149cc902..2f064a8b 100644 --- a/src/main/javassist/tools/Dump.java +++ b/src/main/javassist/tools/Dump.java @@ -17,7 +17,7 @@ package javassist.tools; import java.io.*; import javassist.bytecode.ClassFile; -import javassist.bytecode.ClassFileWriter; +import javassist.bytecode.ClassFilePrinter; /** * Dump is a tool for viewing the class definition in the given @@ -52,6 +52,6 @@ public class Dump { w.getConstPool().print(out); out.println(); out.println("*** members ***"); - ClassFileWriter.print(w, out); + ClassFilePrinter.print(w, out); } } -- 2.39.5