ClassWriter.java revision 3294:9adfb22ff08f
1/* 2 * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27package com.sun.tools.classfile; 28 29import java.io.ByteArrayOutputStream; 30import java.io.DataOutputStream; 31import java.io.File; 32import java.io.FileOutputStream; 33import java.io.IOException; 34import java.io.OutputStream; 35 36import static com.sun.tools.classfile.Annotation.*; 37import static com.sun.tools.classfile.ConstantPool.*; 38import static com.sun.tools.classfile.StackMapTable_attribute.*; 39import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*; 40 41/** 42 * Write a ClassFile data structure to a file or stream. 43 * 44 * <p><b>This is NOT part of any supported API. 45 * If you write code that depends on this, you do so at your own risk. 46 * This code and its internal interfaces are subject to change or 47 * deletion without notice.</b> 48 */ 49public class ClassWriter { 50 public ClassWriter() { 51 attributeWriter = new AttributeWriter(); 52 constantPoolWriter = new ConstantPoolWriter(); 53 out = new ClassOutputStream(); 54 } 55 56 /** 57 * Write a ClassFile data structure to a file. 58 */ 59 public void write(ClassFile classFile, File f) throws IOException { 60 try (FileOutputStream f_out = new FileOutputStream(f)) { 61 write(classFile, f_out); 62 } 63 } 64 65 /** 66 * Write a ClassFile data structure to a stream. 67 */ 68 public void write(ClassFile classFile, OutputStream s) throws IOException { 69 this.classFile = classFile; 70 out.reset(); 71 write(); 72 out.writeTo(s); 73 } 74 75 protected void write() throws IOException { 76 writeHeader(); 77 writeConstantPool(); 78 writeAccessFlags(classFile.access_flags); 79 writeClassInfo(); 80 writeFields(); 81 writeMethods(); 82 writeAttributes(classFile.attributes); 83 } 84 85 protected void writeHeader() { 86 out.writeInt(classFile.magic); 87 out.writeShort(classFile.minor_version); 88 out.writeShort(classFile.major_version); 89 } 90 91 protected void writeAccessFlags(AccessFlags flags) { 92 out.writeShort(flags.flags); 93 } 94 95 protected void writeAttributes(Attributes attributes) { 96 int size = attributes.size(); 97 out.writeShort(size); 98 for (Attribute attr: attributes) 99 attributeWriter.write(attr, out); 100 } 101 102 protected void writeClassInfo() { 103 out.writeShort(classFile.this_class); 104 out.writeShort(classFile.super_class); 105 int[] interfaces = classFile.interfaces; 106 out.writeShort(interfaces.length); 107 for (int i: interfaces) 108 out.writeShort(i); 109 } 110 111 protected void writeDescriptor(Descriptor d) { 112 out.writeShort(d.index); 113 } 114 115 protected void writeConstantPool() { 116 ConstantPool pool = classFile.constant_pool; 117 int size = pool.size(); 118 out.writeShort(size); 119 for (CPInfo cpInfo: pool.entries()) 120 constantPoolWriter.write(cpInfo, out); 121 } 122 123 protected void writeFields() throws IOException { 124 Field[] fields = classFile.fields; 125 out.writeShort(fields.length); 126 for (Field f: fields) 127 writeField(f); 128 } 129 130 protected void writeField(Field f) throws IOException { 131 writeAccessFlags(f.access_flags); 132 out.writeShort(f.name_index); 133 writeDescriptor(f.descriptor); 134 writeAttributes(f.attributes); 135 } 136 137 protected void writeMethods() throws IOException { 138 Method[] methods = classFile.methods; 139 out.writeShort(methods.length); 140 for (Method m: methods) { 141 writeMethod(m); 142 } 143 } 144 145 protected void writeMethod(Method m) throws IOException { 146 writeAccessFlags(m.access_flags); 147 out.writeShort(m.name_index); 148 writeDescriptor(m.descriptor); 149 writeAttributes(m.attributes); 150 } 151 152 protected ClassFile classFile; 153 protected ClassOutputStream out; 154 protected AttributeWriter attributeWriter; 155 protected ConstantPoolWriter constantPoolWriter; 156 157 /** 158 * Subtype of ByteArrayOutputStream with the convenience methods of 159 * a DataOutputStream. Since ByteArrayOutputStream does not throw 160 * IOException, there are no exceptions from the additional 161 * convenience methods either, 162 */ 163 protected static class ClassOutputStream extends ByteArrayOutputStream { 164 public ClassOutputStream() { 165 d = new DataOutputStream(this); 166 } 167 168 public void writeByte(int value) { 169 try { 170 d.writeByte(value); 171 } catch (IOException ignore) { 172 } 173 } 174 175 public void writeShort(int value) { 176 try { 177 d.writeShort(value); 178 } catch (IOException ignore) { 179 } 180 } 181 182 public void writeInt(int value) { 183 try { 184 d.writeInt(value); 185 } catch (IOException ignore) { 186 } 187 } 188 189 public void writeLong(long value) { 190 try { 191 d.writeLong(value); 192 } catch (IOException ignore) { 193 } 194 } 195 196 public void writeFloat(float value) { 197 try { 198 d.writeFloat(value); 199 } catch (IOException ignore) { 200 } 201 } 202 203 public void writeDouble(double value) { 204 try { 205 d.writeDouble(value); 206 } catch (IOException ignore) { 207 } 208 } 209 210 public void writeUTF(String value) { 211 try { 212 d.writeUTF(value); 213 } catch (IOException ignore) { 214 } 215 } 216 217 public void writeTo(ClassOutputStream s) { 218 try { 219 super.writeTo(s); 220 } catch (IOException ignore) { 221 } 222 } 223 224 private final DataOutputStream d; 225 } 226 227 /** 228 * Writer for the entries in the constant pool. 229 */ 230 protected static class ConstantPoolWriter 231 implements ConstantPool.Visitor<Integer,ClassOutputStream> { 232 protected int write(CPInfo info, ClassOutputStream out) { 233 out.writeByte(info.getTag()); 234 return info.accept(this, out); 235 } 236 237 @Override 238 public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) { 239 out.writeShort(info.name_index); 240 return 1; 241 } 242 243 @Override 244 public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) { 245 out.writeDouble(info.value); 246 return 2; 247 } 248 249 @Override 250 public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) { 251 writeRef(info, out); 252 return 1; 253 } 254 255 @Override 256 public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) { 257 out.writeFloat(info.value); 258 return 1; 259 } 260 261 @Override 262 public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) { 263 out.writeInt(info.value); 264 return 1; 265 } 266 267 @Override 268 public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) { 269 writeRef(info, out); 270 return 1; 271 } 272 273 @Override 274 public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out) { 275 out.writeShort(info.bootstrap_method_attr_index); 276 out.writeShort(info.name_and_type_index); 277 return 1; 278 } 279 280 @Override 281 public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) { 282 out.writeLong(info.value); 283 return 2; 284 } 285 286 @Override 287 public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) { 288 out.writeShort(info.name_index); 289 out.writeShort(info.type_index); 290 return 1; 291 } 292 293 @Override 294 public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) { 295 out.writeByte(info.reference_kind.tag); 296 out.writeShort(info.reference_index); 297 return 1; 298 } 299 300 @Override 301 public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) { 302 out.writeShort(info.descriptor_index); 303 return 1; 304 } 305 306 @Override 307 public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) { 308 return writeRef(info, out); 309 } 310 311 @Override 312 public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) { 313 out.writeShort(info.string_index); 314 return 1; 315 } 316 317 @Override 318 public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) { 319 out.writeUTF(info.value); 320 return 1; 321 } 322 323 protected Integer writeRef(CPRefInfo info, ClassOutputStream out) { 324 out.writeShort(info.class_index); 325 out.writeShort(info.name_and_type_index); 326 return 1; 327 } 328 } 329 330 /** 331 * Writer for the different types of attribute. 332 */ 333 protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> { 334 public void write(Attributes attributes, ClassOutputStream out) { 335 int size = attributes.size(); 336 out.writeShort(size); 337 for (Attribute a: attributes) 338 write(a, out); 339 } 340 341 // Note: due to the use of shared resources, this method is not reentrant. 342 public void write(Attribute attr, ClassOutputStream out) { 343 out.writeShort(attr.attribute_name_index); 344 sharedOut.reset(); 345 attr.accept(this, sharedOut); 346 out.writeInt(sharedOut.size()); 347 sharedOut.writeTo(out); 348 } 349 350 protected ClassOutputStream sharedOut = new ClassOutputStream(); 351 protected AnnotationWriter annotationWriter = new AnnotationWriter(); 352 353 @Override 354 public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) { 355 out.write(attr.info, 0, attr.info.length); 356 return null; 357 } 358 359 @Override 360 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) { 361 annotationWriter.write(attr.default_value, out); 362 return null; 363 } 364 365 @Override 366 public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) { 367 out.writeShort(attr.bootstrap_method_specifiers.length); 368 for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) { 369 out.writeShort(bsm.bootstrap_method_ref); 370 int bsm_args_count = bsm.bootstrap_arguments.length; 371 out.writeShort(bsm_args_count); 372 for (int i : bsm.bootstrap_arguments) { 373 out.writeShort(i); 374 } 375 } 376 return null; 377 } 378 379 @Override 380 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) { 381 out.writeShort(attr.character_range_table.length); 382 for (CharacterRangeTable_attribute.Entry e: attr.character_range_table) 383 writeCharacterRangeTableEntry(e, out); 384 return null; 385 } 386 387 protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) { 388 out.writeShort(entry.start_pc); 389 out.writeShort(entry.end_pc); 390 out.writeInt(entry.character_range_start); 391 out.writeInt(entry.character_range_end); 392 out.writeShort(entry.flags); 393 } 394 395 @Override 396 public Void visitCode(Code_attribute attr, ClassOutputStream out) { 397 out.writeShort(attr.max_stack); 398 out.writeShort(attr.max_locals); 399 out.writeInt(attr.code.length); 400 out.write(attr.code, 0, attr.code.length); 401 out.writeShort(attr.exception_table.length); 402 for (Code_attribute.Exception_data e: attr.exception_table) 403 writeExceptionTableEntry(e, out); 404 new AttributeWriter().write(attr.attributes, out); 405 return null; 406 } 407 408 protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) { 409 out.writeShort(exception_data.start_pc); 410 out.writeShort(exception_data.end_pc); 411 out.writeShort(exception_data.handler_pc); 412 out.writeShort(exception_data.catch_type); 413 } 414 415 @Override 416 public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) { 417 out.writeShort(attr.compilationID_index); 418 return null; 419 } 420 421 @Override 422 public Void visitConcealedPackages(ConcealedPackages_attribute attr, ClassOutputStream out) { 423 out.writeShort(attr.packages_count); 424 for (int i: attr.packages_index) 425 out.writeShort(i); 426 return null; 427 } 428 429 @Override 430 public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) { 431 out.writeShort(attr.constantvalue_index); 432 return null; 433 } 434 435 @Override 436 public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) { 437 return null; 438 } 439 440 @Override 441 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) { 442 out.writeShort(attr.class_index); 443 out.writeShort(attr.method_index); 444 return null; 445 } 446 447 @Override 448 public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) { 449 out.writeShort(attr.exception_index_table.length); 450 for (int i: attr.exception_index_table) 451 out.writeShort(i); 452 return null; 453 } 454 455 @Override 456 public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) { 457 out.writeShort(attr.classes.length); 458 for (InnerClasses_attribute.Info info: attr.classes) 459 writeInnerClassesInfo(info, out); 460 return null; 461 } 462 463 @Override 464 public Void visitHashes(Hashes_attribute attr, ClassOutputStream out) { 465 out.writeShort(attr.algorithm_index); 466 out.writeShort(attr.hashes_table.length); 467 for (Hashes_attribute.Entry e: attr.hashes_table) { 468 out.writeShort(e.requires_index); 469 out.writeShort(e.hash_index); 470 } 471 return null; 472 } 473 474 protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) { 475 out.writeShort(info.inner_class_info_index); 476 out.writeShort(info.outer_class_info_index); 477 out.writeShort(info.inner_name_index); 478 writeAccessFlags(info.inner_class_access_flags, out); 479 } 480 481 @Override 482 public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) { 483 out.writeShort(attr.line_number_table.length); 484 for (LineNumberTable_attribute.Entry e: attr.line_number_table) 485 writeLineNumberTableEntry(e, out); 486 return null; 487 } 488 489 protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) { 490 out.writeShort(entry.start_pc); 491 out.writeShort(entry.line_number); 492 } 493 494 @Override 495 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) { 496 out.writeShort(attr.local_variable_table.length); 497 for (LocalVariableTable_attribute.Entry e: attr.local_variable_table) 498 writeLocalVariableTableEntry(e, out); 499 return null; 500 } 501 502 protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) { 503 out.writeShort(entry.start_pc); 504 out.writeShort(entry.length); 505 out.writeShort(entry.name_index); 506 out.writeShort(entry.descriptor_index); 507 out.writeShort(entry.index); 508 } 509 510 @Override 511 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) { 512 out.writeShort(attr.local_variable_table.length); 513 for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table) 514 writeLocalVariableTypeTableEntry(e, out); 515 return null; 516 } 517 518 protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) { 519 out.writeShort(entry.start_pc); 520 out.writeShort(entry.length); 521 out.writeShort(entry.name_index); 522 out.writeShort(entry.signature_index); 523 out.writeShort(entry.index); 524 } 525 526 @Override 527 public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) { 528 out.writeByte(attr.method_parameter_table.length); 529 for (MethodParameters_attribute.Entry e : attr.method_parameter_table) { 530 out.writeShort(e.name_index); 531 out.writeShort(e.flags); 532 } 533 return null; 534 } 535 536 @Override 537 public Void visitMainClass(MainClass_attribute attr, ClassOutputStream out) { 538 out.writeShort(attr.main_class_index); 539 return null; 540 } 541 542 @Override 543 public Void visitModule(Module_attribute attr, ClassOutputStream out) { 544 out.writeShort(attr.requires.length); 545 for (Module_attribute.RequiresEntry e: attr.requires) { 546 out.writeShort(e.requires_index); 547 out.writeShort(e.requires_flags); 548 } 549 out.writeShort(attr.exports.length); 550 for (Module_attribute.ExportsEntry e: attr.exports) { 551 out.writeShort(e.exports_index); 552 out.writeShort(e.exports_to_index.length); 553 for (int index: e.exports_to_index) 554 out.writeShort(index); 555 } 556 out.writeShort(attr.uses_index.length); 557 for (int index: attr.uses_index) 558 out.writeShort(index); 559 out.writeShort(attr.provides.length); 560 for (Module_attribute.ProvidesEntry e: attr.provides) { 561 out.writeShort(e.provides_index); 562 out.writeShort(e.with_index); 563 } 564 return null; 565 } 566 567 @Override 568 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) { 569 annotationWriter.write(attr.annotations, out); 570 return null; 571 } 572 573 @Override 574 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) { 575 annotationWriter.write(attr.annotations, out); 576 return null; 577 } 578 579 @Override 580 public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) { 581 annotationWriter.write(attr.annotations, out); 582 return null; 583 } 584 585 @Override 586 public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) { 587 annotationWriter.write(attr.annotations, out); 588 return null; 589 } 590 591 @Override 592 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) { 593 out.writeByte(attr.parameter_annotations.length); 594 for (Annotation[] annos: attr.parameter_annotations) 595 annotationWriter.write(annos, out); 596 return null; 597 } 598 599 @Override 600 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) { 601 out.writeByte(attr.parameter_annotations.length); 602 for (Annotation[] annos: attr.parameter_annotations) 603 annotationWriter.write(annos, out); 604 return null; 605 } 606 607 @Override 608 public Void visitSignature(Signature_attribute attr, ClassOutputStream out) { 609 out.writeShort(attr.signature_index); 610 return null; 611 } 612 613 @Override 614 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) { 615 out.write(attr.debug_extension, 0, attr.debug_extension.length); 616 return null; 617 } 618 619 @Override 620 public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) { 621 out.writeShort(attr.sourcefile_index); 622 return null; 623 } 624 625 @Override 626 public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) { 627 out.writeShort(attr.sourceID_index); 628 return null; 629 } 630 631 @Override 632 public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) { 633 if (stackMapWriter == null) 634 stackMapWriter = new StackMapTableWriter(); 635 636 out.writeShort(attr.entries.length); 637 for (stack_map_frame f: attr.entries) 638 stackMapWriter.write(f, out); 639 return null; 640 } 641 642 @Override 643 public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) { 644 if (stackMapWriter == null) 645 stackMapWriter = new StackMapTableWriter(); 646 647 out.writeShort(attr.entries.length); 648 for (stack_map_frame f: attr.entries) 649 stackMapWriter.write(f, out); 650 return null; 651 } 652 653 @Override 654 public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) { 655 return null; 656 } 657 658 @Override 659 public Void visitTargetPlatform(TargetPlatform_attribute attr, ClassOutputStream out) { 660 out.writeShort(attr.os_name_index); 661 out.writeShort(attr.os_arch_index); 662 out.writeShort(attr.os_version_index); 663 return null; 664 } 665 666 protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) { 667 sharedOut.writeShort(flags.flags); 668 } 669 670 @Override 671 public Void visitVersion(Version_attribute attr, ClassOutputStream out) { 672 out.writeShort(attr.version_index); 673 return null; 674 } 675 676 protected StackMapTableWriter stackMapWriter; 677 } 678 679 /** 680 * Writer for the frames of StackMap and StackMapTable attributes. 681 */ 682 protected static class StackMapTableWriter 683 implements stack_map_frame.Visitor<Void,ClassOutputStream> { 684 685 public void write(stack_map_frame frame, ClassOutputStream out) { 686 out.write(frame.frame_type); 687 frame.accept(this, out); 688 } 689 690 @Override 691 public Void visit_same_frame(same_frame frame, ClassOutputStream p) { 692 return null; 693 } 694 695 @Override 696 public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) { 697 writeVerificationTypeInfo(frame.stack[0], out); 698 return null; 699 } 700 701 @Override 702 public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) { 703 out.writeShort(frame.offset_delta); 704 writeVerificationTypeInfo(frame.stack[0], out); 705 return null; 706 } 707 708 @Override 709 public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) { 710 out.writeShort(frame.offset_delta); 711 return null; 712 } 713 714 @Override 715 public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) { 716 out.writeShort(frame.offset_delta); 717 return null; 718 } 719 720 @Override 721 public Void visit_append_frame(append_frame frame, ClassOutputStream out) { 722 out.writeShort(frame.offset_delta); 723 for (verification_type_info l: frame.locals) 724 writeVerificationTypeInfo(l, out); 725 return null; 726 } 727 728 @Override 729 public Void visit_full_frame(full_frame frame, ClassOutputStream out) { 730 out.writeShort(frame.offset_delta); 731 out.writeShort(frame.locals.length); 732 for (verification_type_info l: frame.locals) 733 writeVerificationTypeInfo(l, out); 734 out.writeShort(frame.stack.length); 735 for (verification_type_info s: frame.stack) 736 writeVerificationTypeInfo(s, out); 737 return null; 738 } 739 740 protected void writeVerificationTypeInfo(verification_type_info info, 741 ClassOutputStream out) { 742 out.write(info.tag); 743 switch (info.tag) { 744 case ITEM_Top: 745 case ITEM_Integer: 746 case ITEM_Float: 747 case ITEM_Long: 748 case ITEM_Double: 749 case ITEM_Null: 750 case ITEM_UninitializedThis: 751 break; 752 753 case ITEM_Object: 754 Object_variable_info o = (Object_variable_info) info; 755 out.writeShort(o.cpool_index); 756 break; 757 758 case ITEM_Uninitialized: 759 Uninitialized_variable_info u = (Uninitialized_variable_info) info; 760 out.writeShort(u.offset); 761 break; 762 763 default: 764 throw new Error(); 765 } 766 } 767 } 768 769 /** 770 * Writer for annotations and the values they contain. 771 */ 772 protected static class AnnotationWriter 773 implements Annotation.element_value.Visitor<Void,ClassOutputStream> { 774 public void write(Annotation[] annos, ClassOutputStream out) { 775 out.writeShort(annos.length); 776 for (Annotation anno: annos) 777 write(anno, out); 778 } 779 780 public void write(TypeAnnotation[] annos, ClassOutputStream out) { 781 out.writeShort(annos.length); 782 for (TypeAnnotation anno: annos) 783 write(anno, out); 784 } 785 786 public void write(Annotation anno, ClassOutputStream out) { 787 out.writeShort(anno.type_index); 788 out.writeShort(anno.element_value_pairs.length); 789 for (element_value_pair p: anno.element_value_pairs) 790 write(p, out); 791 } 792 793 public void write(TypeAnnotation anno, ClassOutputStream out) { 794 write(anno.position, out); 795 write(anno.annotation, out); 796 } 797 798 public void write(element_value_pair pair, ClassOutputStream out) { 799 out.writeShort(pair.element_name_index); 800 write(pair.value, out); 801 } 802 803 public void write(element_value ev, ClassOutputStream out) { 804 out.writeByte(ev.tag); 805 ev.accept(this, out); 806 } 807 808 @Override 809 public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) { 810 out.writeShort(ev.const_value_index); 811 return null; 812 } 813 814 @Override 815 public Void visitEnum(Enum_element_value ev, ClassOutputStream out) { 816 out.writeShort(ev.type_name_index); 817 out.writeShort(ev.const_name_index); 818 return null; 819 } 820 821 @Override 822 public Void visitClass(Class_element_value ev, ClassOutputStream out) { 823 out.writeShort(ev.class_info_index); 824 return null; 825 } 826 827 @Override 828 public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) { 829 write(ev.annotation_value, out); 830 return null; 831 } 832 833 @Override 834 public Void visitArray(Array_element_value ev, ClassOutputStream out) { 835 out.writeShort(ev.num_values); 836 for (element_value v: ev.values) 837 write(v, out); 838 return null; 839 } 840 841 // TODO: Move this to TypeAnnotation to be closer with similar logic? 842 private void write(TypeAnnotation.Position p, ClassOutputStream out) { 843 out.writeByte(p.type.targetTypeValue()); 844 switch (p.type) { 845 // instanceof 846 case INSTANCEOF: 847 // new expression 848 case NEW: 849 // constructor/method reference receiver 850 case CONSTRUCTOR_REFERENCE: 851 case METHOD_REFERENCE: 852 out.writeShort(p.offset); 853 break; 854 // local variable 855 case LOCAL_VARIABLE: 856 // resource variable 857 case RESOURCE_VARIABLE: 858 int table_length = p.lvarOffset.length; 859 out.writeShort(table_length); 860 for (int i = 0; i < table_length; ++i) { 861 out.writeShort(1); // for table length 862 out.writeShort(p.lvarOffset[i]); 863 out.writeShort(p.lvarLength[i]); 864 out.writeShort(p.lvarIndex[i]); 865 } 866 break; 867 // exception parameter 868 case EXCEPTION_PARAMETER: 869 out.writeShort(p.exception_index); 870 break; 871 // method receiver 872 case METHOD_RECEIVER: 873 // Do nothing 874 break; 875 // type parameters 876 case CLASS_TYPE_PARAMETER: 877 case METHOD_TYPE_PARAMETER: 878 out.writeByte(p.parameter_index); 879 break; 880 // type parameters bounds 881 case CLASS_TYPE_PARAMETER_BOUND: 882 case METHOD_TYPE_PARAMETER_BOUND: 883 out.writeByte(p.parameter_index); 884 out.writeByte(p.bound_index); 885 break; 886 // class extends or implements clause 887 case CLASS_EXTENDS: 888 out.writeShort(p.type_index); 889 break; 890 // throws 891 case THROWS: 892 out.writeShort(p.type_index); 893 break; 894 // method parameter 895 case METHOD_FORMAL_PARAMETER: 896 out.writeByte(p.parameter_index); 897 break; 898 // type cast 899 case CAST: 900 // method/constructor/reference type argument 901 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 902 case METHOD_INVOCATION_TYPE_ARGUMENT: 903 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 904 case METHOD_REFERENCE_TYPE_ARGUMENT: 905 out.writeShort(p.offset); 906 out.writeByte(p.type_index); 907 break; 908 // We don't need to worry about these 909 case METHOD_RETURN: 910 case FIELD: 911 break; 912 case UNKNOWN: 913 throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!"); 914 default: 915 throw new AssertionError("ClassWriter: Unknown target type for position: " + p); 916 } 917 918 { // Append location data for generics/arrays. 919 // TODO: check for overrun? 920 out.writeByte((byte)p.location.size()); 921 for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location)) 922 out.writeByte((byte)i); 923 } 924 } 925 } 926} 927