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