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 FileOutputStream f_out = new FileOutputStream(f); 61 try { 62 write(classFile, f_out); 63 } finally { 64 f_out.close(); 65 } 66 } 67 68 /** 69 * Write a ClassFile data structure to a stream. 70 */ 71 public void write(ClassFile classFile, OutputStream s) throws IOException { 72 this.classFile = classFile; 73 out.reset(); 74 write(); 75 out.writeTo(s); 76 } 77 78 protected void write() throws IOException { 79 writeHeader(); 80 writeConstantPool(); 81 writeAccessFlags(classFile.access_flags); 82 writeClassInfo(); 83 writeFields(); 84 writeMethods(); 85 writeAttributes(classFile.attributes); 86 } 87 88 protected void writeHeader() { 89 out.writeInt(classFile.magic); 90 out.writeShort(classFile.minor_version); 91 out.writeShort(classFile.major_version); 92 } 93 94 protected void writeAccessFlags(AccessFlags flags) { 95 out.writeShort(flags.flags); 96 } 97 98 protected void writeAttributes(Attributes attributes) { 99 int size = attributes.size(); 100 out.writeShort(size); 101 for (Attribute attr: attributes) 102 attributeWriter.write(attr, out); 103 } 104 105 protected void writeClassInfo() { 106 out.writeShort(classFile.this_class); 107 out.writeShort(classFile.super_class); 108 int[] interfaces = classFile.interfaces; 109 out.writeShort(interfaces.length); 110 for (int i: interfaces) 111 out.writeShort(i); 112 } 113 114 protected void writeDescriptor(Descriptor d) { 115 out.writeShort(d.index); 116 } 117 118 protected void writeConstantPool() { 119 ConstantPool pool = classFile.constant_pool; 120 int size = pool.size(); 121 out.writeShort(size); 122 for (CPInfo cpInfo: pool.entries()) 123 constantPoolWriter.write(cpInfo, out); 124 } 125 126 protected void writeFields() throws IOException { 127 Field[] fields = classFile.fields; 128 out.writeShort(fields.length); 129 for (Field f: fields) 130 writeField(f); 131 } 132 133 protected void writeField(Field f) throws IOException { 134 writeAccessFlags(f.access_flags); 135 out.writeShort(f.name_index); 136 writeDescriptor(f.descriptor); 137 writeAttributes(f.attributes); 138 } 139 140 protected void writeMethods() throws IOException { 141 Method[] methods = classFile.methods; 142 out.writeShort(methods.length); 143 for (Method m: methods) { 144 writeMethod(m); 145 } 146 } 147 148 protected void writeMethod(Method m) throws IOException { 149 writeAccessFlags(m.access_flags); 150 out.writeShort(m.name_index); 151 writeDescriptor(m.descriptor); 152 writeAttributes(m.attributes); 153 } 154 155 protected ClassFile classFile; 156 protected ClassOutputStream out; 157 protected AttributeWriter attributeWriter; 158 protected ConstantPoolWriter constantPoolWriter; 159 160 /** 161 * Subtype of ByteArrayOutputStream with the convenience methods of 162 * a DataOutputStream. Since ByteArrayOutputStream does not throw 163 * IOException, there are no exceptions from the additional 164 * convenience methods either, 165 */ 166 protected static class ClassOutputStream extends ByteArrayOutputStream { 167 public ClassOutputStream() { 168 d = new DataOutputStream(this); 169 } 170 171 public void writeByte(int value) { 172 try { 173 d.writeByte(value); 174 } catch (IOException ignore) { 175 } 176 } 177 178 public void writeShort(int value) { 179 try { 180 d.writeShort(value); 181 } catch (IOException ignore) { 182 } 183 } 184 185 public void writeInt(int value) { 186 try { 187 d.writeInt(value); 188 } catch (IOException ignore) { 189 } 190 } 191 192 public void writeLong(long value) { 193 try { 194 d.writeLong(value); 195 } catch (IOException ignore) { 196 } 197 } 198 199 public void writeFloat(float value) { 200 try { 201 d.writeFloat(value); 202 } catch (IOException ignore) { 203 } 204 } 205 206 public void writeDouble(double value) { 207 try { 208 d.writeDouble(value); 209 } catch (IOException ignore) { 210 } 211 } 212 213 public void writeUTF(String value) { 214 try { 215 d.writeUTF(value); 216 } catch (IOException ignore) { 217 } 218 } 219 220 public void writeTo(ClassOutputStream s) { 221 try { 222 super.writeTo(s); 223 } catch (IOException ignore) { 224 } 225 } 226 227 private DataOutputStream d; 228 } 229 230 /** 231 * Writer for the entries in the constant pool. 232 */ 233 protected static class ConstantPoolWriter 234 implements ConstantPool.Visitor<Integer,ClassOutputStream> { 235 protected int write(CPInfo info, ClassOutputStream out) { 236 out.writeByte(info.getTag()); 237 return info.accept(this, out); 238 } 239 240 public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) { 241 out.writeShort(info.name_index); 242 return 1; 243 } 244 245 public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) { 246 out.writeDouble(info.value); 247 return 2; 248 } 249 250 public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) { 251 writeRef(info, out); 252 return 1; 253 } 254 255 public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) { 256 out.writeFloat(info.value); 257 return 1; 258 } 259 260 public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) { 261 out.writeInt(info.value); 262 return 1; 263 } 264 265 public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) { 266 writeRef(info, out); 267 return 1; 268 } 269 270 public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out) { 271 out.writeShort(info.bootstrap_method_attr_index); 272 out.writeShort(info.name_and_type_index); 273 return 1; 274 } 275 276 public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) { 277 out.writeLong(info.value); 278 return 2; 279 } 280 281 public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) { 282 out.writeShort(info.name_index); 283 out.writeShort(info.type_index); 284 return 1; 285 } 286 287 public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) { 288 out.writeByte(info.reference_kind.tag); 289 out.writeShort(info.reference_index); 290 return 1; 291 } 292 293 public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) { 294 out.writeShort(info.descriptor_index); 295 return 1; 296 } 297 298 public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) { 299 return writeRef(info, out); 300 } 301 302 public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) { 303 out.writeShort(info.string_index); 304 return 1; 305 } 306 307 public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) { 308 out.writeUTF(info.value); 309 return 1; 310 } 311 312 protected Integer writeRef(CPRefInfo info, ClassOutputStream out) { 313 out.writeShort(info.class_index); 314 out.writeShort(info.name_and_type_index); 315 return 1; 316 } 317 } 318 319 /** 320 * Writer for the different types of attribute. 321 */ 322 protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> { 323 public void write(Attributes attributes, ClassOutputStream out) { 324 int size = attributes.size(); 325 out.writeShort(size); 326 for (Attribute a: attributes) 327 write(a, out); 328 } 329 330 // Note: due to the use of shared resources, this method is not reentrant. 331 public void write(Attribute attr, ClassOutputStream out) { 332 out.writeShort(attr.attribute_name_index); 333 sharedOut.reset(); 334 attr.accept(this, sharedOut); 335 out.writeInt(sharedOut.size()); 336 sharedOut.writeTo(out); 337 } 338 339 protected ClassOutputStream sharedOut = new ClassOutputStream(); 340 protected AnnotationWriter annotationWriter = new AnnotationWriter(); 341 342 public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) { 343 out.write(attr.info, 0, attr.info.length); 344 return null; 345 } 346 347 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) { 348 annotationWriter.write(attr.default_value, out); 349 return null; 350 } 351 352 public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) { 353 out.writeShort(attr.bootstrap_method_specifiers.length); 354 for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) { 355 out.writeShort(bsm.bootstrap_method_ref); 356 int bsm_args_count = bsm.bootstrap_arguments.length; 357 out.writeShort(bsm_args_count); 358 for (int i : bsm.bootstrap_arguments) { 359 out.writeShort(i); 360 } 361 } 362 return null; 363 } 364 365 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) { 366 out.writeShort(attr.character_range_table.length); 367 for (CharacterRangeTable_attribute.Entry e: attr.character_range_table) 368 writeCharacterRangeTableEntry(e, out); 369 return null; 370 } 371 372 protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) { 373 out.writeShort(entry.start_pc); 374 out.writeShort(entry.end_pc); 375 out.writeInt(entry.character_range_start); 376 out.writeInt(entry.character_range_end); 377 out.writeShort(entry.flags); 378 } 379 380 public Void visitCode(Code_attribute attr, ClassOutputStream out) { 381 out.writeShort(attr.max_stack); 382 out.writeShort(attr.max_locals); 383 out.writeInt(attr.code.length); 384 out.write(attr.code, 0, attr.code.length); 385 out.writeShort(attr.exception_table.length); 386 for (Code_attribute.Exception_data e: attr.exception_table) 387 writeExceptionTableEntry(e, out); 388 new AttributeWriter().write(attr.attributes, out); 389 return null; 390 } 391 392 protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) { 393 out.writeShort(exception_data.start_pc); 394 out.writeShort(exception_data.end_pc); 395 out.writeShort(exception_data.handler_pc); 396 out.writeShort(exception_data.catch_type); 397 } 398 399 public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) { 400 out.writeShort(attr.compilationID_index); 401 return null; 402 } 403 404 public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) { 405 out.writeShort(attr.constantvalue_index); 406 return null; 407 } 408 409 public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) { 410 return null; 411 } 412 413 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) { 414 out.writeShort(attr.class_index); 415 out.writeShort(attr.method_index); 416 return null; 417 } 418 419 public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) { 420 out.writeShort(attr.exception_index_table.length); 421 for (int i: attr.exception_index_table) 422 out.writeShort(i); 423 return null; 424 } 425 426 public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) { 427 out.writeShort(attr.classes.length); 428 for (InnerClasses_attribute.Info info: attr.classes) 429 writeInnerClassesInfo(info, out); 430 return null; 431 } 432 433 protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) { 434 out.writeShort(info.inner_class_info_index); 435 out.writeShort(info.outer_class_info_index); 436 out.writeShort(info.inner_name_index); 437 writeAccessFlags(info.inner_class_access_flags, out); 438 } 439 440 public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) { 441 out.writeShort(attr.line_number_table.length); 442 for (LineNumberTable_attribute.Entry e: attr.line_number_table) 443 writeLineNumberTableEntry(e, out); 444 return null; 445 } 446 447 protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) { 448 out.writeShort(entry.start_pc); 449 out.writeShort(entry.line_number); 450 } 451 452 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) { 453 out.writeShort(attr.local_variable_table.length); 454 for (LocalVariableTable_attribute.Entry e: attr.local_variable_table) 455 writeLocalVariableTableEntry(e, out); 456 return null; 457 } 458 459 protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) { 460 out.writeShort(entry.start_pc); 461 out.writeShort(entry.length); 462 out.writeShort(entry.name_index); 463 out.writeShort(entry.descriptor_index); 464 out.writeShort(entry.index); 465 } 466 467 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) { 468 out.writeShort(attr.local_variable_table.length); 469 for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table) 470 writeLocalVariableTypeTableEntry(e, out); 471 return null; 472 } 473 474 protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) { 475 out.writeShort(entry.start_pc); 476 out.writeShort(entry.length); 477 out.writeShort(entry.name_index); 478 out.writeShort(entry.signature_index); 479 out.writeShort(entry.index); 480 } 481 482 public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) { 483 out.writeByte(attr.method_parameter_table.length); 484 for (MethodParameters_attribute.Entry e : attr.method_parameter_table) { 485 out.writeShort(e.name_index); 486 out.writeShort(e.flags); 487 } 488 return null; 489 } 490 491 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) { 492 annotationWriter.write(attr.annotations, out); 493 return null; 494 } 495 496 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) { 497 annotationWriter.write(attr.annotations, out); 498 return null; 499 } 500 501 public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) { 502 annotationWriter.write(attr.annotations, out); 503 return null; 504 } 505 506 public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) { 507 annotationWriter.write(attr.annotations, out); 508 return null; 509 } 510 511 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) { 512 out.writeByte(attr.parameter_annotations.length); 513 for (Annotation[] annos: attr.parameter_annotations) 514 annotationWriter.write(annos, out); 515 return null; 516 } 517 518 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) { 519 out.writeByte(attr.parameter_annotations.length); 520 for (Annotation[] annos: attr.parameter_annotations) 521 annotationWriter.write(annos, out); 522 return null; 523 } 524 525 public Void visitSignature(Signature_attribute attr, ClassOutputStream out) { 526 out.writeShort(attr.signature_index); 527 return null; 528 } 529 530 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) { 531 out.write(attr.debug_extension, 0, attr.debug_extension.length); 532 return null; 533 } 534 535 public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) { 536 out.writeShort(attr.sourcefile_index); 537 return null; 538 } 539 540 public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) { 541 out.writeShort(attr.sourceID_index); 542 return null; 543 } 544 545 public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) { 546 if (stackMapWriter == null) 547 stackMapWriter = new StackMapTableWriter(); 548 549 out.writeShort(attr.entries.length); 550 for (stack_map_frame f: attr.entries) 551 stackMapWriter.write(f, out); 552 return null; 553 } 554 555 public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) { 556 if (stackMapWriter == null) 557 stackMapWriter = new StackMapTableWriter(); 558 559 out.writeShort(attr.entries.length); 560 for (stack_map_frame f: attr.entries) 561 stackMapWriter.write(f, out); 562 return null; 563 } 564 565 public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) { 566 return null; 567 } 568 569 protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) { 570 sharedOut.writeShort(flags.flags); 571 } 572 573 protected StackMapTableWriter stackMapWriter; 574 } 575 576 /** 577 * Writer for the frames of StackMap and StackMapTable attributes. 578 */ 579 protected static class StackMapTableWriter 580 implements stack_map_frame.Visitor<Void,ClassOutputStream> { 581 582 public void write(stack_map_frame frame, ClassOutputStream out) { 583 out.write(frame.frame_type); 584 frame.accept(this, out); 585 } 586 587 public Void visit_same_frame(same_frame frame, ClassOutputStream p) { 588 return null; 589 } 590 591 public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) { 592 writeVerificationTypeInfo(frame.stack[0], out); 593 return null; 594 } 595 596 public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) { 597 out.writeShort(frame.offset_delta); 598 writeVerificationTypeInfo(frame.stack[0], out); 599 return null; 600 } 601 602 public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) { 603 out.writeShort(frame.offset_delta); 604 return null; 605 } 606 607 public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) { 608 out.writeShort(frame.offset_delta); 609 return null; 610 } 611 612 public Void visit_append_frame(append_frame frame, ClassOutputStream out) { 613 out.writeShort(frame.offset_delta); 614 for (verification_type_info l: frame.locals) 615 writeVerificationTypeInfo(l, out); 616 return null; 617 } 618 619 public Void visit_full_frame(full_frame frame, ClassOutputStream out) { 620 out.writeShort(frame.offset_delta); 621 out.writeShort(frame.locals.length); 622 for (verification_type_info l: frame.locals) 623 writeVerificationTypeInfo(l, out); 624 out.writeShort(frame.stack.length); 625 for (verification_type_info s: frame.stack) 626 writeVerificationTypeInfo(s, out); 627 return null; 628 } 629 630 protected void writeVerificationTypeInfo(verification_type_info info, 631 ClassOutputStream out) { 632 out.write(info.tag); 633 switch (info.tag) { 634 case ITEM_Top: 635 case ITEM_Integer: 636 case ITEM_Float: 637 case ITEM_Long: 638 case ITEM_Double: 639 case ITEM_Null: 640 case ITEM_UninitializedThis: 641 break; 642 643 case ITEM_Object: 644 Object_variable_info o = (Object_variable_info) info; 645 out.writeShort(o.cpool_index); 646 break; 647 648 case ITEM_Uninitialized: 649 Uninitialized_variable_info u = (Uninitialized_variable_info) info; 650 out.writeShort(u.offset); 651 break; 652 653 default: 654 throw new Error(); 655 } 656 } 657 } 658 659 /** 660 * Writer for annotations and the values they contain. 661 */ 662 protected static class AnnotationWriter 663 implements Annotation.element_value.Visitor<Void,ClassOutputStream> { 664 public void write(Annotation[] annos, ClassOutputStream out) { 665 out.writeShort(annos.length); 666 for (Annotation anno: annos) 667 write(anno, out); 668 } 669 670 public void write(TypeAnnotation[] annos, ClassOutputStream out) { 671 out.writeShort(annos.length); 672 for (TypeAnnotation anno: annos) 673 write(anno, out); 674 } 675 676 public void write(Annotation anno, ClassOutputStream out) { 677 out.writeShort(anno.type_index); 678 out.writeShort(anno.element_value_pairs.length); 679 for (element_value_pair p: anno.element_value_pairs) 680 write(p, out); 681 } 682 683 public void write(TypeAnnotation anno, ClassOutputStream out) { 684 write(anno.position, out); 685 write(anno.annotation, out); 686 } 687 688 public void write(element_value_pair pair, ClassOutputStream out) { 689 out.writeShort(pair.element_name_index); 690 write(pair.value, out); 691 } 692 693 public void write(element_value ev, ClassOutputStream out) { 694 out.writeByte(ev.tag); 695 ev.accept(this, out); 696 } 697 698 public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) { 699 out.writeShort(ev.const_value_index); 700 return null; 701 } 702 703 public Void visitEnum(Enum_element_value ev, ClassOutputStream out) { 704 out.writeShort(ev.type_name_index); 705 out.writeShort(ev.const_name_index); 706 return null; 707 } 708 709 public Void visitClass(Class_element_value ev, ClassOutputStream out) { 710 out.writeShort(ev.class_info_index); 711 return null; 712 } 713 714 public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) { 715 write(ev.annotation_value, out); 716 return null; 717 } 718 719 public Void visitArray(Array_element_value ev, ClassOutputStream out) { 720 out.writeShort(ev.num_values); 721 for (element_value v: ev.values) 722 write(v, out); 723 return null; 724 } 725 726 // TODO: Move this to TypeAnnotation to be closer with similar logic? 727 private void write(TypeAnnotation.Position p, ClassOutputStream out) { 728 out.writeByte(p.type.targetTypeValue()); 729 switch (p.type) { 730 // type cast 731 case CAST: 732 // instanceof 733 case INSTANCEOF: 734 // new expression 735 case NEW: 736 out.writeShort(p.offset); 737 break; 738 // local variable 739 case LOCAL_VARIABLE: 740 // resource variable 741 case RESOURCE_VARIABLE: 742 int table_length = p.lvarOffset.length; 743 out.writeShort(table_length); 744 for (int i = 0; i < table_length; ++i) { 745 out.writeShort(1); // for table length 746 out.writeShort(p.lvarOffset[i]); 747 out.writeShort(p.lvarLength[i]); 748 out.writeShort(p.lvarIndex[i]); 749 } 750 break; 751 // exception parameter 752 case EXCEPTION_PARAMETER: 753 out.writeByte(p.exception_index); 754 break; 755 // method receiver 756 case METHOD_RECEIVER: 757 // Do nothing 758 break; 759 // type parameters 760 case CLASS_TYPE_PARAMETER: 761 case METHOD_TYPE_PARAMETER: 762 out.writeByte(p.parameter_index); 763 break; 764 // type parameters bounds 765 case CLASS_TYPE_PARAMETER_BOUND: 766 case METHOD_TYPE_PARAMETER_BOUND: 767 out.writeByte(p.parameter_index); 768 out.writeByte(p.bound_index); 769 break; 770 // class extends or implements clause 771 case CLASS_EXTENDS: 772 out.writeByte(p.type_index); 773 break; 774 // throws 775 case THROWS: 776 out.writeByte(p.type_index); 777 break; 778 // method parameter 779 case METHOD_FORMAL_PARAMETER: 780 out.writeByte(p.parameter_index); 781 break; 782 // method/constructor/reference type argument 783 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 784 case METHOD_INVOCATION_TYPE_ARGUMENT: 785 case METHOD_REFERENCE_TYPE_ARGUMENT: 786 out.writeShort(p.offset); 787 out.writeByte(p.type_index); 788 break; 789 // We don't need to worry about these 790 case METHOD_RETURN: 791 case FIELD: 792 break; 793 // lambda formal parameter 794 case LAMBDA_FORMAL_PARAMETER: 795 out.writeByte(p.parameter_index); 796 break; 797 case UNKNOWN: 798 throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!"); 799 default: 800 throw new AssertionError("ClassWriter: Unknown target type for position: " + p); 801 } 802 803 { // Append location data for generics/arrays. 804 // TODO: check for overrun? 805 out.writeByte((byte)p.location.size()); 806 for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location)) 807 out.writeByte((byte)i); 808 } 809 } 810 } 811 }