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