1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.bytecode;
18 
19 import java.io.DataOutputStream;
20 import java.io.IOException;
21 import java.io.OutputStream;
22 
23 /**
24  * A quick class-file writer.  This is useful when a generated
25  * class file is simple and the code generation should be fast.
26  *
27  * <p>Example:
28  *
29  * <blockquote><pre>
30  * ClassFileWriter cfw = new ClassFileWriter(ClassFile.JAVA_4, 0);
31  * ConstPoolWriter cpw = cfw.getConstPool();
32  *
33  * FieldWriter fw = cfw.getFieldWriter();
34  * fw.add(AccessFlag.PUBLIC, "value", "I", null);
35  * fw.add(AccessFlag.PUBLIC, "value2", "J", null);
36  *
37  * int thisClass = cpw.addClassInfo("sample/Test");
38  * int superClass = cpw.addClassInfo("java/lang/Object");
39  *
40  * MethodWriter mw = cfw.getMethodWriter();
41  *
42  * mw.begin(AccessFlag.PUBLIC, MethodInfo.nameInit, "()V", null, null);
43  * mw.add(Opcode.ALOAD_0);
44  * mw.add(Opcode.INVOKESPECIAL);
45  * int signature = cpw.addNameAndTypeInfo(MethodInfo.nameInit, "()V");
46  * mw.add16(cpw.addMethodrefInfo(superClass, signature));
47  * mw.add(Opcode.RETURN);
48  * mw.codeEnd(1, 1);
49  * mw.end(null, null);
50  *
51  * mw.begin(AccessFlag.PUBLIC, "one", "()I", null, null);
52  * mw.add(Opcode.ICONST_1);
53  * mw.add(Opcode.IRETURN);
54  * mw.codeEnd(1, 1);
55  * mw.end(null, null);
56  *
57  * byte[] classfile = cfw.end(AccessFlag.PUBLIC, thisClass, superClass,
58  *                            null, null);
59  * </pre></blockquote>
60  *
61  * <p>The code above generates the following class:
62  *
63  * <blockquote><pre>
64  * package sample;
65  * public class Test {
66  *     public int value;
67  *     public long value2;
68  *     public Test() { super(); }
69  *     public one() { return 1; }
70  * }
71  * </pre></blockquote>
72  *
73  * @since 3.13
74  */
75 public class ClassFileWriter {
76     private ByteStream output;
77     private ConstPoolWriter constPool;
78     private FieldWriter fields;
79     private MethodWriter methods;
80     int thisClass, superClass;
81 
82     /**
83      * Constructs a class file writer.
84      *
85      * @param major     the major version ({@link ClassFile#JAVA_4}, {@link ClassFile#JAVA_5}, ...).
86      * @param minor     the minor version (0 for JDK 1.3 and later).
87      */
ClassFileWriter(int major, int minor)88     public ClassFileWriter(int major, int minor) {
89         output = new ByteStream(512);
90         output.writeInt(0xCAFEBABE); // magic
91         output.writeShort(minor);
92         output.writeShort(major);
93         constPool = new ConstPoolWriter(output);
94         fields = new FieldWriter(constPool);
95         methods = new MethodWriter(constPool);
96 
97     }
98 
99     /**
100      * Returns a constant pool.
101      */
getConstPool()102     public ConstPoolWriter getConstPool() { return constPool; }
103 
104     /**
105      * Returns a filed writer.
106      */
getFieldWriter()107     public FieldWriter getFieldWriter() { return fields; }
108 
109     /**
110      * Returns a method writer.
111      */
getMethodWriter()112     public MethodWriter getMethodWriter() { return methods; }
113 
114     /**
115      * Ends writing and returns the contents of the class file.
116      *
117      * @param accessFlags       access flags.
118      * @param thisClass         this class.  an index indicating its <code>CONSTANT_Class_info</code>.
119      * @param superClass        super class.  an index indicating its <code>CONSTANT_Class_info</code>.
120      * @param interfaces        implemented interfaces.
121      *                          index numbers indicating their <code>ClassInfo</code>.
122      *                          It may be null.
123      * @param aw        attributes of the class file.  May be null.
124      *
125      * @see AccessFlag
126      */
end(int accessFlags, int thisClass, int superClass, int[] interfaces, AttributeWriter aw)127     public byte[] end(int accessFlags, int thisClass, int superClass,
128                       int[] interfaces, AttributeWriter aw) {
129         constPool.end();
130         output.writeShort(accessFlags);
131         output.writeShort(thisClass);
132         output.writeShort(superClass);
133         if (interfaces == null)
134             output.writeShort(0);
135         else {
136             int n = interfaces.length;
137             output.writeShort(n);
138             for (int i = 0; i < n; i++)
139                 output.writeShort(interfaces[i]);
140         }
141 
142         output.enlarge(fields.dataSize() + methods.dataSize() + 6);
143         try {
144             output.writeShort(fields.size());
145             fields.write(output);
146 
147             output.writeShort(methods.numOfMethods());
148             methods.write(output);
149         }
150         catch (IOException e) {}
151 
152         writeAttribute(output, aw, 0);
153         return output.toByteArray();
154     }
155 
156     /**
157      * Ends writing and writes the contents of the class file into the
158      * given output stream.
159      *
160      * @param accessFlags       access flags.
161      * @param thisClass         this class.  an index indicating its <code>CONSTANT_Class_info</code>.
162      * @param superClass        super class.  an index indicating its <code>CONSTANT_Class_info</code>.
163      * @param interfaces        implemented interfaces.
164      *                          index numbers indicating their <code>CONSTATNT_Class_info</code>.
165      *                          It may be null.
166      * @param aw        attributes of the class file.  May be null.
167      *
168      * @see AccessFlag
169      */
end(DataOutputStream out, int accessFlags, int thisClass, int superClass, int[] interfaces, AttributeWriter aw)170     public void end(DataOutputStream out,
171                     int accessFlags, int thisClass, int superClass,
172                     int[] interfaces, AttributeWriter aw)
173         throws IOException
174     {
175         constPool.end();
176         output.writeTo(out);
177         out.writeShort(accessFlags);
178         out.writeShort(thisClass);
179         out.writeShort(superClass);
180         if (interfaces == null)
181             out.writeShort(0);
182         else {
183             int n = interfaces.length;
184             out.writeShort(n);
185             for (int i = 0; i < n; i++)
186                 out.writeShort(interfaces[i]);
187         }
188 
189         out.writeShort(fields.size());
190         fields.write(out);
191 
192         out.writeShort(methods.numOfMethods());
193         methods.write(out);
194         if (aw == null)
195             out.writeShort(0);
196         else {
197             out.writeShort(aw.size());
198             aw.write(out);
199         }
200     }
201 
202     /**
203      * This writes attributes.
204      *
205      * <p>For example, the following object writes a synthetic attribute:
206      *
207      * <pre>
208      * ConstPoolWriter cpw = ...;
209      * final int tag = cpw.addUtf8Info("Synthetic");
210      * AttributeWriter aw = new AttributeWriter() {
211      *     public int size() {
212      *         return 1;
213      *     }
214      *     public void write(DataOutputStream out) throws java.io.IOException {
215      *         out.writeShort(tag);
216      *         out.writeInt(0);
217      *     }
218      * };
219      * </pre>
220      */
221     public static interface AttributeWriter {
222         /**
223          * Returns the number of attributes that this writer will
224          * write.
225          */
size()226         public int size();
227 
228         /**
229          * Writes all the contents of the attributes.  The binary representation
230          * of the contents is an array of <code>attribute_info</code>.
231          */
write(DataOutputStream out)232         public void write(DataOutputStream out) throws IOException;
233     }
234 
writeAttribute(ByteStream bs, AttributeWriter aw, int attrCount)235     static void writeAttribute(ByteStream bs, AttributeWriter aw, int attrCount) {
236         if (aw == null) {
237             bs.writeShort(attrCount);
238             return;
239         }
240 
241         bs.writeShort(aw.size() + attrCount);
242         DataOutputStream dos = new DataOutputStream(bs);
243         try {
244             aw.write(dos);
245             dos.flush();
246         }
247         catch (IOException e) {}
248     }
249 
250     /**
251      * Field.
252      */
253     public static final class FieldWriter {
254         protected ByteStream output;
255         protected ConstPoolWriter constPool;
256         private int fieldCount;
257 
FieldWriter(ConstPoolWriter cp)258         FieldWriter(ConstPoolWriter cp) {
259             output = new ByteStream(128);
260             constPool = cp;
261             fieldCount = 0;
262         }
263 
264         /**
265          * Adds a new field.
266          *
267          * @param accessFlags       access flags.
268          * @param name              the field name.
269          * @param descriptor        the field type.
270          * @param aw                the attributes of the field.  may be null.
271          * @see AccessFlag
272          */
add(int accessFlags, String name, String descriptor, AttributeWriter aw)273         public void add(int accessFlags, String name, String descriptor, AttributeWriter aw) {
274             int nameIndex = constPool.addUtf8Info(name);
275             int descIndex = constPool.addUtf8Info(descriptor);
276             add(accessFlags, nameIndex, descIndex, aw);
277         }
278 
279         /**
280          * Adds a new field.
281          *
282          * @param accessFlags       access flags.
283          * @param name              the field name.  an index indicating its <code>CONSTANT_Utf8_info</code>.
284          * @param descriptor        the field type.  an index indicating its <code>CONSTANT_Utf8_info</code>.
285          * @param aw                the attributes of the field.  may be null.
286          * @see AccessFlag
287          */
add(int accessFlags, int name, int descriptor, AttributeWriter aw)288         public void add(int accessFlags, int name, int descriptor, AttributeWriter aw) {
289             ++fieldCount;
290             output.writeShort(accessFlags);
291             output.writeShort(name);
292             output.writeShort(descriptor);
293             writeAttribute(output, aw, 0);
294         }
295 
size()296         int size() { return fieldCount; }
297 
dataSize()298         int dataSize() { return output.size(); }
299 
300         /**
301          * Writes the added fields.
302          */
write(OutputStream out)303         void write(OutputStream out) throws IOException {
304             output.writeTo(out);
305         }
306     }
307 
308     /**
309      * Method.
310      */
311     public static final class MethodWriter {
312         protected ByteStream output;
313         protected ConstPoolWriter constPool;
314         private int methodCount;
315         protected int codeIndex;
316         protected int throwsIndex;
317         protected int stackIndex;
318 
319         private int startPos;
320         private boolean isAbstract;
321         private int catchPos;
322         private int catchCount;
323 
MethodWriter(ConstPoolWriter cp)324         MethodWriter(ConstPoolWriter cp) {
325             output = new ByteStream(256);
326             constPool = cp;
327             methodCount = 0;
328             codeIndex = 0;
329             throwsIndex = 0;
330             stackIndex = 0;
331         }
332 
333         /**
334          * Starts Adding a new method.
335          *
336          * @param accessFlags       access flags.
337          * @param name              the method name.
338          * @param descriptor        the method signature.
339          * @param exceptions        throws clause.  It may be null.
340          *                          The class names must be the JVM-internal
341          *                          representations like <code>java/lang/Exception</code>.
342          * @param aw                attributes to the <code>Method_info</code>.
343          */
begin(int accessFlags, String name, String descriptor, String[] exceptions, AttributeWriter aw)344         public void begin(int accessFlags, String name, String descriptor,
345                         String[] exceptions, AttributeWriter aw) {
346             int nameIndex = constPool.addUtf8Info(name);
347             int descIndex = constPool.addUtf8Info(descriptor);
348             int[] intfs;
349             if (exceptions == null)
350                 intfs = null;
351             else
352                 intfs = constPool.addClassInfo(exceptions);
353 
354             begin(accessFlags, nameIndex, descIndex, intfs, aw);
355         }
356 
357         /**
358          * Starts adding a new method.
359          *
360          * @param accessFlags       access flags.
361          * @param name              the method name.  an index indicating its <code>CONSTANT_Utf8_info</code>.
362          * @param descriptor        the field type.  an index indicating its <code>CONSTANT_Utf8_info</code>.
363          * @param exceptions        throws clause.  indexes indicating <code>CONSTANT_Class_info</code>s.
364          *                          It may be null.
365          * @param aw                attributes to the <code>Method_info</code>.
366          */
begin(int accessFlags, int name, int descriptor, int[] exceptions, AttributeWriter aw)367         public void begin(int accessFlags, int name, int descriptor, int[] exceptions, AttributeWriter aw) {
368             ++methodCount;
369             output.writeShort(accessFlags);
370             output.writeShort(name);
371             output.writeShort(descriptor);
372             isAbstract = (accessFlags & AccessFlag.ABSTRACT) != 0;
373 
374             int attrCount = isAbstract ? 0 : 1;
375             if (exceptions != null)
376                 ++attrCount;
377 
378             writeAttribute(output, aw, attrCount);
379 
380             if (exceptions != null)
381                 writeThrows(exceptions);
382 
383             if (!isAbstract) {
384                 if (codeIndex == 0)
385                     codeIndex = constPool.addUtf8Info(CodeAttribute.tag);
386 
387                 startPos = output.getPos();
388                 output.writeShort(codeIndex);
389                 output.writeBlank(12);   // attribute_length, maxStack, maxLocals, code_lenth
390             }
391 
392             catchPos = -1;
393             catchCount = 0;
394         }
395 
writeThrows(int[] exceptions)396         private void writeThrows(int[] exceptions) {
397             if (throwsIndex == 0)
398                 throwsIndex = constPool.addUtf8Info(ExceptionsAttribute.tag);
399 
400             output.writeShort(throwsIndex);
401             output.writeInt(exceptions.length * 2 + 2);
402             output.writeShort(exceptions.length);
403             for (int i = 0; i < exceptions.length; i++)
404                 output.writeShort(exceptions[i]);
405         }
406 
407         /**
408          * Appends an 8bit value of bytecode.
409          *
410          * @see Opcode
411          */
add(int b)412         public void add(int b) {
413             output.write(b);
414         }
415 
416         /**
417          * Appends a 16bit value of bytecode.
418          */
add16(int b)419         public void add16(int b) {
420             output.writeShort(b);
421         }
422 
423         /**
424          * Appends a 32bit value of bytecode.
425          */
add32(int b)426         public void add32(int b) {
427             output.writeInt(b);
428         }
429 
430         /**
431          * Appends a invokevirtual, inovkespecial, or invokestatic bytecode.
432          *
433          * @see Opcode
434          */
addInvoke(int opcode, String targetClass, String methodName, String descriptor)435         public void addInvoke(int opcode, String targetClass, String methodName,
436                               String descriptor) {
437             int target = constPool.addClassInfo(targetClass);
438             int nt = constPool.addNameAndTypeInfo(methodName, descriptor);
439             int method = constPool.addMethodrefInfo(target, nt);
440             add(opcode);
441             add16(method);
442         }
443 
444         /**
445          * Ends appending bytecode.
446          */
codeEnd(int maxStack, int maxLocals)447         public void codeEnd(int maxStack, int maxLocals) {
448             if (!isAbstract) {
449                 output.writeShort(startPos + 6, maxStack);
450                 output.writeShort(startPos + 8, maxLocals);
451                 output.writeInt(startPos + 10, output.getPos() - startPos - 14);  // code_length
452                 catchPos = output.getPos();
453                 catchCount = 0;
454                 output.writeShort(0);   // number of catch clauses
455             }
456         }
457 
458         /**
459          * Appends an <code>exception_table</code> entry to the
460          * <code>Code_attribute</code>.  This method is available
461          * only after the <code>codeEnd</code> method is called.
462          *
463          * @param catchType     an index indicating a <code>CONSTANT_Class_info</code>.
464          */
addCatch(int startPc, int endPc, int handlerPc, int catchType)465         public void addCatch(int startPc, int endPc, int handlerPc, int catchType) {
466             ++catchCount;
467             output.writeShort(startPc);
468             output.writeShort(endPc);
469             output.writeShort(handlerPc);
470             output.writeShort(catchType);
471         }
472 
473         /**
474          * Ends adding a new method.  The <code>add</code> method must be
475          * called before the <code>end</code> method is called.
476          *
477          * @param smap              a stack map table.  may be null.
478          * @param aw                attributes to the <code>Code_attribute</code>.
479          *                          may be null.
480          */
end(StackMapTable.Writer smap, AttributeWriter aw)481         public void end(StackMapTable.Writer smap, AttributeWriter aw) {
482             if (isAbstract)
483                 return;
484 
485             // exception_table_length
486             output.writeShort(catchPos, catchCount);
487 
488             int attrCount = smap == null ? 0 : 1;
489             writeAttribute(output, aw, attrCount);
490 
491             if (smap != null) {
492                 if (stackIndex == 0)
493                     stackIndex = constPool.addUtf8Info(StackMapTable.tag);
494 
495                 output.writeShort(stackIndex);
496                 byte[] data = smap.toByteArray();
497                 output.writeInt(data.length);
498                 output.write(data);
499             }
500 
501             // Code attribute_length
502             output.writeInt(startPos + 2, output.getPos() - startPos - 6);
503         }
504 
505         /**
506          * Returns the length of the bytecode that has been added so far.
507          *
508          * @return      the length in bytes.
509          * @since 3.19
510          */
size()511         public int size() { return output.getPos() - startPos - 14; }
512 
numOfMethods()513         int numOfMethods() { return methodCount; }
514 
dataSize()515         int dataSize() { return output.size(); }
516 
517         /**
518          * Writes the added methods.
519          */
write(OutputStream out)520         void write(OutputStream out) throws IOException {
521             output.writeTo(out);
522         }
523     }
524 
525     /**
526      * Constant Pool.
527      */
528     public static final class ConstPoolWriter {
529         ByteStream output;
530         protected int startPos;
531         protected int num;
532 
ConstPoolWriter(ByteStream out)533         ConstPoolWriter(ByteStream out) {
534             output = out;
535             startPos = out.getPos();
536             num = 1;
537             output.writeShort(1);   // number of entries
538         }
539 
540         /**
541          * Makes <code>CONSTANT_Class_info</code> objects for each class name.
542          *
543          * @return an array of indexes indicating <code>CONSTANT_Class_info</code>s.
544          */
addClassInfo(String[] classNames)545         public int[] addClassInfo(String[] classNames) {
546             int n = classNames.length;
547             int[] result = new int[n];
548             for (int i = 0; i < n; i++)
549                 result[i] = addClassInfo(classNames[i]);
550 
551             return result;
552         }
553 
554         /**
555          * Adds a new <code>CONSTANT_Class_info</code> structure.
556          *
557          * <p>This also adds a <code>CONSTANT_Utf8_info</code> structure
558          * for storing the class name.
559          *
560          * @param jvmname   the JVM-internal representation of a class name.
561          *                  e.g. <code>java/lang/Object</code>.
562          * @return          the index of the added entry.
563          */
addClassInfo(String jvmname)564         public int addClassInfo(String jvmname) {
565             int utf8 = addUtf8Info(jvmname);
566             output.write(ClassInfo.tag);
567             output.writeShort(utf8);
568             return num++;
569         }
570 
571         /**
572          * Adds a new <code>CONSTANT_Class_info</code> structure.
573          *
574          * @param name      <code>name_index</code>
575          * @return          the index of the added entry.
576          */
addClassInfo(int name)577         public int addClassInfo(int name) {
578             output.write(ClassInfo.tag);
579             output.writeShort(name);
580             return num++;
581         }
582 
583         /**
584          * Adds a new <code>CONSTANT_NameAndType_info</code> structure.
585          *
586          * @param name      <code>name_index</code>
587          * @param type      <code>descriptor_index</code>
588          * @return          the index of the added entry.
589          */
addNameAndTypeInfo(String name, String type)590         public int addNameAndTypeInfo(String name, String type) {
591             return addNameAndTypeInfo(addUtf8Info(name), addUtf8Info(type));
592         }
593 
594         /**
595          * Adds a new <code>CONSTANT_NameAndType_info</code> structure.
596          *
597          * @param name      <code>name_index</code>
598          * @param type      <code>descriptor_index</code>
599          * @return          the index of the added entry.
600          */
addNameAndTypeInfo(int name, int type)601         public int addNameAndTypeInfo(int name, int type) {
602             output.write(NameAndTypeInfo.tag);
603             output.writeShort(name);
604             output.writeShort(type);
605             return num++;
606         }
607 
608         /**
609          * Adds a new <code>CONSTANT_Fieldref_info</code> structure.
610          *
611          * @param classInfo         <code>class_index</code>
612          * @param nameAndTypeInfo   <code>name_and_type_index</code>.
613          * @return          the index of the added entry.
614          */
addFieldrefInfo(int classInfo, int nameAndTypeInfo)615         public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) {
616             output.write(FieldrefInfo.tag);
617             output.writeShort(classInfo);
618             output.writeShort(nameAndTypeInfo);
619             return num++;
620         }
621 
622         /**
623          * Adds a new <code>CONSTANT_Methodref_info</code> structure.
624          *
625          * @param classInfo         <code>class_index</code>
626          * @param nameAndTypeInfo   <code>name_and_type_index</code>.
627          * @return          the index of the added entry.
628          */
addMethodrefInfo(int classInfo, int nameAndTypeInfo)629         public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) {
630             output.write(MethodrefInfo.tag);
631             output.writeShort(classInfo);
632             output.writeShort(nameAndTypeInfo);
633             return num++;
634         }
635 
636         /**
637          * Adds a new <code>CONSTANT_InterfaceMethodref_info</code>
638          * structure.
639          *
640          * @param classInfo         <code>class_index</code>
641          * @param nameAndTypeInfo   <code>name_and_type_index</code>.
642          * @return          the index of the added entry.
643          */
addInterfaceMethodrefInfo(int classInfo, int nameAndTypeInfo)644         public int addInterfaceMethodrefInfo(int classInfo,
645                                              int nameAndTypeInfo) {
646             output.write(InterfaceMethodrefInfo.tag);
647             output.writeShort(classInfo);
648             output.writeShort(nameAndTypeInfo);
649             return num++;
650         }
651 
652         /**
653          * Adds a new <code>CONSTANT_MethodHandle_info</code>
654          * structure.
655          *
656          * @param kind      <code>reference_kind</code>
657          *                  such as {@link ConstPool#REF_invokeStatic <code>REF_invokeStatic</code>}.
658          * @param index     <code>reference_index</code>.
659          * @return          the index of the added entry.
660          *
661          * @since 3.17.1
662          */
addMethodHandleInfo(int kind, int index)663         public int addMethodHandleInfo(int kind, int index) {
664             output.write(MethodHandleInfo.tag);
665             output.write(kind);
666             output.writeShort(index);
667             return num++;
668         }
669 
670         /**
671          * Adds a new <code>CONSTANT_MethodType_info</code>
672          * structure.
673          *
674          * @param desc      <code>descriptor_index</code>.
675          * @return          the index of the added entry.
676          *
677          * @since 3.17.1
678          */
addMethodTypeInfo(int desc)679         public int addMethodTypeInfo(int desc) {
680             output.write(MethodTypeInfo.tag);
681             output.writeShort(desc);
682             return num++;
683         }
684 
685         /**
686          * Adds a new <code>CONSTANT_InvokeDynamic_info</code>
687          * structure.
688          *
689          * @param bootstrap         <code>bootstrap_method_attr_index</code>.
690          * @param nameAndTypeInfo   <code>name_and_type_index</code>.
691          * @return                  the index of the added entry.
692          *
693          * @since 3.17.1
694          */
addInvokeDynamicInfo(int bootstrap, int nameAndTypeInfo)695         public int addInvokeDynamicInfo(int bootstrap,
696                                         int nameAndTypeInfo) {
697             output.write(InvokeDynamicInfo.tag);
698             output.writeShort(bootstrap);
699             output.writeShort(nameAndTypeInfo);
700             return num++;
701         }
702 
703         /**
704          * Adds a new <code>CONSTANT_String_info</code>
705          * structure.
706          *
707          * <p>This also adds a new <code>CONSTANT_Utf8_info</code>
708          * structure.
709          *
710          * @return          the index of the added entry.
711          */
addStringInfo(String str)712         public int addStringInfo(String str) {
713             int utf8 = addUtf8Info(str);
714             output.write(StringInfo.tag);
715             output.writeShort(utf8);
716             return num++;
717         }
718 
719         /**
720          * Adds a new <code>CONSTANT_Integer_info</code>
721          * structure.
722          *
723          * @return          the index of the added entry.
724          */
addIntegerInfo(int i)725         public int addIntegerInfo(int i) {
726             output.write(IntegerInfo.tag);
727             output.writeInt(i);
728             return num++;
729         }
730 
731         /**
732          * Adds a new <code>CONSTANT_Float_info</code>
733          * structure.
734          *
735          * @return          the index of the added entry.
736          */
addFloatInfo(float f)737         public int addFloatInfo(float f) {
738             output.write(FloatInfo.tag);
739             output.writeFloat(f);
740             return num++;
741         }
742 
743         /**
744          * Adds a new <code>CONSTANT_Long_info</code>
745          * structure.
746          *
747          * @return          the index of the added entry.
748          */
addLongInfo(long l)749         public int addLongInfo(long l) {
750             output.write(LongInfo.tag);
751             output.writeLong(l);
752             int n = num;
753             num += 2;
754             return n;
755         }
756 
757         /**
758          * Adds a new <code>CONSTANT_Double_info</code>
759          * structure.
760          *
761          * @return          the index of the added entry.
762          */
addDoubleInfo(double d)763         public int addDoubleInfo(double d) {
764             output.write(DoubleInfo.tag);
765             output.writeDouble(d);
766             int n = num;
767             num += 2;
768             return n;
769         }
770 
771         /**
772          * Adds a new <code>CONSTANT_Utf8_info</code>
773          * structure.
774          *
775          * @return          the index of the added entry.
776          */
addUtf8Info(String utf8)777         public int addUtf8Info(String utf8) {
778             output.write(Utf8Info.tag);
779             output.writeUTF(utf8);
780             return num++;
781         }
782 
783         /**
784          * Writes the contents of this class pool.
785          */
end()786         void end() {
787             output.writeShort(startPos, num);
788         }
789     }
790 }
791