You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ClassFileWriter.java 23KB

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