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 }