1 2 /* 3 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package com.sun.tools.classfile; 28 29 import java.io.ByteArrayOutputStream; 30 import java.io.DataOutputStream; 31 import java.io.File; 32 import java.io.FileOutputStream; 33 import java.io.IOException; 34 import java.io.OutputStream; 35 36 import static com.sun.tools.classfile.Annotation.*; 37 import static com.sun.tools.classfile.ConstantPool.*; 38 import static com.sun.tools.classfile.StackMapTable_attribute.*; 39 import 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 */ 49 public 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 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 public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) { 238 out.writeShort(info.name_index); 239 return 1; 240 } 241 242 public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) { 243 out.writeDouble(info.value); 244 return 2; 245 } 246 247 public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) { 248 writeRef(info, out); 249 return 1; 250 } 251 252 public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) { 253 out.writeFloat(info.value); 254 return 1; 255 } 256 257 public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) { 258 out.writeInt(info.value); 259 return 1; 260 } 261 262 public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) { 263 writeRef(info, out); 264 return 1; 265 } 266 267 public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out) { 268 out.writeShort(info.bootstrap_method_attr_index); 269 out.writeShort(info.name_and_type_index); 270 return 1; 271 } 272 273 public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) { 274 out.writeLong(info.value); 275 return 2; 276 } 277 278 public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) { 279 out.writeShort(info.name_index); 280 out.writeShort(info.type_index); 281 return 1; 282 } 283 284 public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) { 285 out.writeByte(info.reference_kind.tag); 286 out.writeShort(info.reference_index); 287 return 1; 288 } 289 290 public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) { 291 out.writeShort(info.descriptor_index); 292 return 1; 293 } 294 295 public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) { 296 return writeRef(info, out); 297 } 298 299 public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) { 300 out.writeShort(info.string_index); 301 return 1; 302 } 303 304 public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) { 305 out.writeUTF(info.value); 306 return 1; 307 } 308 309 protected Integer writeRef(CPRefInfo info, ClassOutputStream out) { 310 out.writeShort(info.class_index); 311 out.writeShort(info.name_and_type_index); 312 return 1; 313 } 314 } 315 316 /** 317 * Writer for the different types of attribute. 318 */ 319 protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> { 320 public void write(Attributes attributes, ClassOutputStream out) { 321 int size = attributes.size(); 322 out.writeShort(size); 323 for (Attribute a: attributes) 324 write(a, out); 325 } 326 327 // Note: due to the use of shared resources, this method is not reentrant. 328 public void write(Attribute attr, ClassOutputStream out) { 329 out.writeShort(attr.attribute_name_index); 330 sharedOut.reset(); 331 attr.accept(this, sharedOut); 332 out.writeInt(sharedOut.size()); 333 sharedOut.writeTo(out); 334 } 335 336 protected ClassOutputStream sharedOut = new ClassOutputStream(); 337 protected AnnotationWriter annotationWriter = new AnnotationWriter(); 338 339 public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) { 340 out.write(attr.info, 0, attr.info.length); 341 return null; 342 } 343 344 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) { 345 annotationWriter.write(attr.default_value, out); 346 return null; 347 } 348 349 public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) { 350 out.writeShort(attr.bootstrap_method_specifiers.length); 351 for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) { 352 out.writeShort(bsm.bootstrap_method_ref); 353 int bsm_args_count = bsm.bootstrap_arguments.length; 354 out.writeShort(bsm_args_count); 355 for (int i : bsm.bootstrap_arguments) { 356 out.writeShort(i); 357 } 358 } 359 return null; 360 } 361 362 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) { 363 out.writeShort(attr.character_range_table.length); 364 for (CharacterRangeTable_attribute.Entry e: attr.character_range_table) 365 writeCharacterRangeTableEntry(e, out); 366 return null; 367 } 368 369 protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) { 370 out.writeShort(entry.start_pc); 371 out.writeShort(entry.end_pc); 372 out.writeInt(entry.character_range_start); 373 out.writeInt(entry.character_range_end); 374 out.writeShort(entry.flags); 375 } 376 377 public Void visitCode(Code_attribute attr, ClassOutputStream out) { 378 out.writeShort(attr.max_stack); 379 out.writeShort(attr.max_locals); 380 out.writeInt(attr.code.length); 381 out.write(attr.code, 0, attr.code.length); 382 out.writeShort(attr.exception_table.length); 383 for (Code_attribute.Exception_data e: attr.exception_table) 384 writeExceptionTableEntry(e, out); 385 new AttributeWriter().write(attr.attributes, out); 386 return null; 387 } 388 389 protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) { 390 out.writeShort(exception_data.start_pc); 391 out.writeShort(exception_data.end_pc); 392 out.writeShort(exception_data.handler_pc); 393 out.writeShort(exception_data.catch_type); 394 } 395 396 public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) { 397 out.writeShort(attr.compilationID_index); 398 return null; 399 } 400 401 public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) { 402 out.writeShort(attr.constantvalue_index); 403 return null; 404 } 405 406 public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) { 407 return null; 408 } 409 410 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) { 411 out.writeShort(attr.class_index); 412 out.writeShort(attr.method_index); 413 return null; 414 } 415 416 public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) { 417 out.writeShort(attr.exception_index_table.length); 418 for (int i: attr.exception_index_table) 419 out.writeShort(i); 420 return null; 421 } 422 423 public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) { 424 out.writeShort(attr.classes.length); 425 for (InnerClasses_attribute.Info info: attr.classes) 426 writeInnerClassesInfo(info, out); 427 return null; 428 } 429 430 protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) { 431 out.writeShort(info.inner_class_info_index); 432 out.writeShort(info.outer_class_info_index); 433 out.writeShort(info.inner_name_index); 434 writeAccessFlags(info.inner_class_access_flags, out); 435 } 436 437 public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) { 438 out.writeShort(attr.line_number_table.length); 439 for (LineNumberTable_attribute.Entry e: attr.line_number_table) 440 writeLineNumberTableEntry(e, out); 441 return null; 442 } 443 444 protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) { 445 out.writeShort(entry.start_pc); 446 out.writeShort(entry.line_number); 447 } 448 449 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) { 450 out.writeShort(attr.local_variable_table.length); 451 for (LocalVariableTable_attribute.Entry e: attr.local_variable_table) 452 writeLocalVariableTableEntry(e, out); 453 return null; 454 } 455 456 protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) { 457 out.writeShort(entry.start_pc); 458 out.writeShort(entry.length); 459 out.writeShort(entry.name_index); 460 out.writeShort(entry.descriptor_index); 461 out.writeShort(entry.index); 462 } 463 464 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) { 465 out.writeShort(attr.local_variable_table.length); 466 for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table) 467 writeLocalVariableTypeTableEntry(e, out); 468 return null; 469 } 470 471 protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) { 472 out.writeShort(entry.start_pc); 473 out.writeShort(entry.length); 474 out.writeShort(entry.name_index); 475 out.writeShort(entry.signature_index); 476 out.writeShort(entry.index); 477 } 478 479 public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) { 480 out.writeByte(attr.method_parameter_table.length); 481 for (MethodParameters_attribute.Entry e : attr.method_parameter_table) { 482 out.writeShort(e.name_index); 483 out.writeShort(e.flags); 484 } 485 return null; 486 } 487 488 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) { 489 annotationWriter.write(attr.annotations, out); 490 return null; 491 } 492 493 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) { 494 annotationWriter.write(attr.annotations, out); 495 return null; 496 } 497 498 public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) { 499 annotationWriter.write(attr.annotations, out); 500 return null; 501 } 502 503 public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) { 504 annotationWriter.write(attr.annotations, out); 505 return null; 506 } 507 508 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) { 509 out.writeByte(attr.parameter_annotations.length); 510 for (Annotation[] annos: attr.parameter_annotations) 511 annotationWriter.write(annos, out); 512 return null; 513 } 514 515 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) { 516 out.writeByte(attr.parameter_annotations.length); 517 for (Annotation[] annos: attr.parameter_annotations) 518 annotationWriter.write(annos, out); 519 return null; 520 } 521 522 public Void visitSignature(Signature_attribute attr, ClassOutputStream out) { 523 out.writeShort(attr.signature_index); 524 return null; 525 } 526 527 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) { 528 out.write(attr.debug_extension, 0, attr.debug_extension.length); 529 return null; 530 } 531 532 public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) { 533 out.writeShort(attr.sourcefile_index); 534 return null; 535 } 536 537 public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) { 538 out.writeShort(attr.sourceID_index); 539 return null; 540 } 541 542 public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) { 543 if (stackMapWriter == null) 544 stackMapWriter = new StackMapTableWriter(); 545 546 out.writeShort(attr.entries.length); 547 for (stack_map_frame f: attr.entries) 548 stackMapWriter.write(f, out); 549 return null; 550 } 551 552 public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) { 553 if (stackMapWriter == null) 554 stackMapWriter = new StackMapTableWriter(); 555 556 out.writeShort(attr.entries.length); 557 for (stack_map_frame f: attr.entries) 558 stackMapWriter.write(f, out); 559 return null; 560 } 561 562 public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) { 563 return null; 564 } 565 566 protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) { 567 sharedOut.writeShort(flags.flags); 568 } 569 570 protected StackMapTableWriter stackMapWriter; 571 } 572 573 /** 574 * Writer for the frames of StackMap and StackMapTable attributes. 575 */ 576 protected static class StackMapTableWriter 577 implements stack_map_frame.Visitor<Void,ClassOutputStream> { 578 579 public void write(stack_map_frame frame, ClassOutputStream out) { 580 out.write(frame.frame_type); 581 frame.accept(this, out); 582 } 583 584 public Void visit_same_frame(same_frame frame, ClassOutputStream p) { 585 return null; 586 } 587 588 public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) { 589 writeVerificationTypeInfo(frame.stack[0], out); 590 return null; 591 } 592 593 public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) { 594 out.writeShort(frame.offset_delta); 595 writeVerificationTypeInfo(frame.stack[0], out); 596 return null; 597 } 598 599 public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) { 600 out.writeShort(frame.offset_delta); 601 return null; 602 } 603 604 public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) { 605 out.writeShort(frame.offset_delta); 606 return null; 607 } 608 609 public Void visit_append_frame(append_frame frame, ClassOutputStream out) { 610 out.writeShort(frame.offset_delta); 611 for (verification_type_info l: frame.locals) 612 writeVerificationTypeInfo(l, out); 613 return null; 614 } 615 616 public Void visit_full_frame(full_frame frame, ClassOutputStream out) { 617 out.writeShort(frame.offset_delta); 618 out.writeShort(frame.locals.length); 619 for (verification_type_info l: frame.locals) 620 writeVerificationTypeInfo(l, out); 621 out.writeShort(frame.stack.length); 622 for (verification_type_info s: frame.stack) 623 writeVerificationTypeInfo(s, out); 624 return null; 625 } 626 627 protected void writeVerificationTypeInfo(verification_type_info info, 628 ClassOutputStream out) { 629 out.write(info.tag); 630 switch (info.tag) { 631 case ITEM_Top: 632 case ITEM_Integer: 633 case ITEM_Float: 634 case ITEM_Long: 635 case ITEM_Double: 636 case ITEM_Null: 637 case ITEM_UninitializedThis: 638 break; 639 640 case ITEM_Object: 641 Object_variable_info o = (Object_variable_info) info; 642 out.writeShort(o.cpool_index); 643 break; 644 645 case ITEM_Uninitialized: 646 Uninitialized_variable_info u = (Uninitialized_variable_info) info; 647 out.writeShort(u.offset); 648 break; 649 650 default: 651 throw new Error(); 652 } 653 } 654 } 655 656 /** 657 * Writer for annotations and the values they contain. 658 */ 659 protected static class AnnotationWriter 660 implements Annotation.element_value.Visitor<Void,ClassOutputStream> { 661 public void write(Annotation[] annos, ClassOutputStream out) { 662 out.writeShort(annos.length); 663 for (Annotation anno: annos) 664 write(anno, out); 665 } 666 667 public void write(TypeAnnotation[] annos, ClassOutputStream out) { 668 out.writeShort(annos.length); 669 for (TypeAnnotation anno: annos) 670 write(anno, out); 671 } 672 673 public void write(Annotation anno, ClassOutputStream out) { 674 out.writeShort(anno.type_index); 675 out.writeShort(anno.element_value_pairs.length); 676 for (element_value_pair p: anno.element_value_pairs) 677 write(p, out); 678 } 679 680 public void write(TypeAnnotation anno, ClassOutputStream out) { 681 write(anno.position, out); 682 write(anno.annotation, out); 683 } 684 685 public void write(element_value_pair pair, ClassOutputStream out) { 686 out.writeShort(pair.element_name_index); 687 write(pair.value, out); 688 } 689 690 public void write(element_value ev, ClassOutputStream out) { 691 out.writeByte(ev.tag); 692 ev.accept(this, out); 693 } 694 695 public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) { 696 out.writeShort(ev.const_value_index); 697 return null; 698 } 699 700 public Void visitEnum(Enum_element_value ev, ClassOutputStream out) { 701 out.writeShort(ev.type_name_index); 702 out.writeShort(ev.const_name_index); 703 return null; 704 } 705 706 public Void visitClass(Class_element_value ev, ClassOutputStream out) { 707 out.writeShort(ev.class_info_index); 708 return null; 709 } 710 711 public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) { 712 write(ev.annotation_value, out); 713 return null; 714 } 715 716 public Void visitArray(Array_element_value ev, ClassOutputStream out) { 717 out.writeShort(ev.num_values); 718 for (element_value v: ev.values) 719 write(v, out); 720 return null; 721 } 722 723 // TODO: Move this to TypeAnnotation to be closer with similar logic? 724 private void write(TypeAnnotation.Position p, ClassOutputStream out) { 725 out.writeByte(p.type.targetTypeValue()); 726 switch (p.type) { 727 // instanceof 728 case INSTANCEOF: 729 // new expression 730 case NEW: 731 // constructor/method reference receiver 732 case CONSTRUCTOR_REFERENCE: 733 case METHOD_REFERENCE: 734 out.writeShort(p.offset); 735 break; 736 // local variable 737 case LOCAL_VARIABLE: 738 // resource variable 739 case RESOURCE_VARIABLE: 740 int table_length = p.lvarOffset.length; 741 out.writeShort(table_length); 742 for (int i = 0; i < table_length; ++i) { 743 out.writeShort(1); // for table length 744 out.writeShort(p.lvarOffset[i]); 745 out.writeShort(p.lvarLength[i]); 746 out.writeShort(p.lvarIndex[i]); 747 } 748 break; 749 // exception parameter 750 case EXCEPTION_PARAMETER: 751 out.writeShort(p.exception_index); 752 break; 753 // method receiver 754 case METHOD_RECEIVER: 755 // Do nothing 756 break; 757 // type parameters 758 case CLASS_TYPE_PARAMETER: 759 case METHOD_TYPE_PARAMETER: 760 out.writeByte(p.parameter_index); 761 break; 762 // type parameters bounds 763 case CLASS_TYPE_PARAMETER_BOUND: 764 case METHOD_TYPE_PARAMETER_BOUND: 765 out.writeByte(p.parameter_index); 766 out.writeByte(p.bound_index); 767 break; 768 // class extends or implements clause 769 case CLASS_EXTENDS: 770 out.writeShort(p.type_index); 771 break; 772 // throws 773 case THROWS: 774 out.writeShort(p.type_index); 775 break; 776 // method parameter 777 case METHOD_FORMAL_PARAMETER: 778 out.writeByte(p.parameter_index); 779 break; 780 // type cast 781 case CAST: 782 // method/constructor/reference type argument 783 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 784 case METHOD_INVOCATION_TYPE_ARGUMENT: 785 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 786 case METHOD_REFERENCE_TYPE_ARGUMENT: 787 out.writeShort(p.offset); 788 out.writeByte(p.type_index); 789 break; 790 // We don't need to worry about these 791 case METHOD_RETURN: 792 case FIELD: 793 break; 794 case UNKNOWN: 795 throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!"); 796 default: 797 throw new AssertionError("ClassWriter: Unknown target type for position: " + p); 798 } 799 800 { // Append location data for generics/arrays. 801 // TODO: check for overrun? 802 out.writeByte((byte)p.location.size()); 803 for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location)) 804 out.writeByte((byte)i); 805 } 806 } 807 } 808 }