ClassWriter.java revision 3170:dc017a37aac5
1/*
2 * Copyright (c) 2008, 2013, 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 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}
809