1 /*
2  * Copyright (c) 2008, 2020, 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 
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 {
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      */
write(ClassFile classFile, File f)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      */
write(ClassFile classFile, OutputStream s)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 
write()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 
writeHeader()91     protected void writeHeader() {
92         out.writeInt(classFile.magic);
93         out.writeShort(classFile.minor_version);
94         out.writeShort(classFile.major_version);
95     }
96 
writeAccessFlags(AccessFlags flags)97     protected void writeAccessFlags(AccessFlags flags) {
98         out.writeShort(flags.flags);
99     }
100 
writeAttributes(Attributes attributes)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 
writeClassInfo()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 
writeDescriptor(Descriptor d)117     protected void writeDescriptor(Descriptor d) {
118         out.writeShort(d.index);
119     }
120 
writeConstantPool()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 
writeFields()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 
writeField(Field f)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 
writeMethods()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 
writeMethod(Method m)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 {
ClassOutputStream()170         public ClassOutputStream() {
171             d = new DataOutputStream(this);
172         }
173 
writeByte(int value)174         public void writeByte(int value) {
175             try {
176                 d.writeByte(value);
177             } catch (IOException ignore) {
178             }
179         }
180 
writeShort(int value)181         public void writeShort(int value) {
182             try {
183                 d.writeShort(value);
184             } catch (IOException ignore) {
185             }
186         }
187 
writeInt(int value)188         public void writeInt(int value) {
189             try {
190                 d.writeInt(value);
191             } catch (IOException ignore) {
192             }
193         }
194 
writeLong(long value)195         public void writeLong(long value) {
196             try {
197                 d.writeLong(value);
198             } catch (IOException ignore) {
199             }
200         }
201 
writeFloat(float value)202         public void writeFloat(float value) {
203             try {
204                 d.writeFloat(value);
205             } catch (IOException ignore) {
206             }
207         }
208 
writeDouble(double value)209         public void writeDouble(double value) {
210             try {
211                 d.writeDouble(value);
212             } catch (IOException ignore) {
213             }
214         }
215 
writeUTF(String value)216         public void writeUTF(String value) {
217             try {
218                 d.writeUTF(value);
219             } catch (IOException ignore) {
220             }
221         }
222 
writeTo(ClassOutputStream s)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> {
write(CPInfo info, ClassOutputStream out)238         protected int write(CPInfo info, ClassOutputStream out) {
239             out.writeByte(info.getTag());
240             return info.accept(this, out);
241         }
242 
243         @Override
visitClass(CONSTANT_Class_info info, ClassOutputStream out)244         public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) {
245             out.writeShort(info.name_index);
246             return 1;
247         }
248 
249         @Override
visitDouble(CONSTANT_Double_info info, ClassOutputStream out)250         public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) {
251             out.writeDouble(info.value);
252             return 2;
253         }
254 
255         @Override
visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out)256         public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) {
257             writeRef(info, out);
258             return 1;
259         }
260 
261         @Override
visitFloat(CONSTANT_Float_info info, ClassOutputStream out)262         public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) {
263             out.writeFloat(info.value);
264             return 1;
265         }
266 
267         @Override
visitInteger(CONSTANT_Integer_info info, ClassOutputStream out)268         public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) {
269             out.writeInt(info.value);
270             return 1;
271         }
272 
273         @Override
visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out)274         public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) {
275             writeRef(info, out);
276             return 1;
277         }
278 
279         @Override
visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out)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 
visitDynamicConstant(CONSTANT_Dynamic_info info, ClassOutputStream out)286         public Integer visitDynamicConstant(CONSTANT_Dynamic_info info, ClassOutputStream out) {
287             out.writeShort(info.bootstrap_method_attr_index);
288             out.writeShort(info.name_and_type_index);
289             return 1;
290         }
291 
292         @Override
visitLong(CONSTANT_Long_info info, ClassOutputStream out)293         public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) {
294             out.writeLong(info.value);
295             return 2;
296         }
297 
298         @Override
visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out)299         public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) {
300             out.writeByte(info.reference_kind.tag);
301             out.writeShort(info.reference_index);
302             return 1;
303         }
304 
305         @Override
visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out)306         public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) {
307             out.writeShort(info.descriptor_index);
308             return 1;
309         }
310 
311         @Override
visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out)312         public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) {
313             return writeRef(info, out);
314         }
315 
316         @Override
visitModule(CONSTANT_Module_info info, ClassOutputStream out)317         public Integer visitModule(CONSTANT_Module_info info, ClassOutputStream out) {
318             out.writeShort(info.name_index);
319             return 1;
320         }
321 
322         @Override
visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out)323         public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) {
324             out.writeShort(info.name_index);
325             out.writeShort(info.type_index);
326             return 1;
327         }
328 
329         @Override
visitPackage(CONSTANT_Package_info info, ClassOutputStream out)330         public Integer visitPackage(CONSTANT_Package_info info, ClassOutputStream out) {
331             out.writeShort(info.name_index);
332             return 1;
333         }
334 
335         @Override
visitString(CONSTANT_String_info info, ClassOutputStream out)336         public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) {
337             out.writeShort(info.string_index);
338             return 1;
339         }
340 
341         @Override
visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out)342         public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) {
343             out.writeUTF(info.value);
344             return 1;
345         }
346 
writeRef(CPRefInfo info, ClassOutputStream out)347         protected Integer writeRef(CPRefInfo info, ClassOutputStream out) {
348             out.writeShort(info.class_index);
349             out.writeShort(info.name_and_type_index);
350             return 1;
351         }
352     }
353 
354     /**
355      * Writer for the different types of attribute.
356      */
357     protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> {
write(Attributes attributes, ClassOutputStream out)358         public void write(Attributes attributes, ClassOutputStream out) {
359             int size = attributes.size();
360             out.writeShort(size);
361             for (Attribute a: attributes)
362                 write(a, out);
363         }
364 
365         // Note: due to the use of shared resources, this method is not reentrant.
write(Attribute attr, ClassOutputStream out)366         public void write(Attribute attr, ClassOutputStream out) {
367             out.writeShort(attr.attribute_name_index);
368             sharedOut.reset();
369             attr.accept(this, sharedOut);
370             out.writeInt(sharedOut.size());
371             sharedOut.writeTo(out);
372         }
373 
374         protected ClassOutputStream sharedOut = new ClassOutputStream();
375         protected AnnotationWriter annotationWriter = new AnnotationWriter();
376 
377         @Override
visitDefault(DefaultAttribute attr, ClassOutputStream out)378         public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) {
379             out.write(attr.info, 0, attr.info.length);
380             return null;
381         }
382 
383         @Override
visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out)384         public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) {
385             annotationWriter.write(attr.default_value, out);
386             return null;
387         }
388 
389         @Override
visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out)390         public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) {
391             out.writeShort(attr.bootstrap_method_specifiers.length);
392             for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) {
393                 out.writeShort(bsm.bootstrap_method_ref);
394                 int bsm_args_count = bsm.bootstrap_arguments.length;
395                 out.writeShort(bsm_args_count);
396                 for (int i : bsm.bootstrap_arguments) {
397                     out.writeShort(i);
398                 }
399             }
400             return null;
401         }
402 
403         @Override
visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out)404         public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) {
405             out.writeShort(attr.character_range_table.length);
406             for (CharacterRangeTable_attribute.Entry e: attr.character_range_table)
407                 writeCharacterRangeTableEntry(e, out);
408             return null;
409         }
410 
writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out)411         protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) {
412             out.writeShort(entry.start_pc);
413             out.writeShort(entry.end_pc);
414             out.writeInt(entry.character_range_start);
415             out.writeInt(entry.character_range_end);
416             out.writeShort(entry.flags);
417         }
418 
419         @Override
visitCode(Code_attribute attr, ClassOutputStream out)420         public Void visitCode(Code_attribute attr, ClassOutputStream out) {
421             out.writeShort(attr.max_stack);
422             out.writeShort(attr.max_locals);
423             out.writeInt(attr.code.length);
424             out.write(attr.code, 0, attr.code.length);
425             out.writeShort(attr.exception_table.length);
426             for (Code_attribute.Exception_data e: attr.exception_table)
427                 writeExceptionTableEntry(e, out);
428             new AttributeWriter().write(attr.attributes, out);
429             return null;
430         }
431 
writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out)432         protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) {
433             out.writeShort(exception_data.start_pc);
434             out.writeShort(exception_data.end_pc);
435             out.writeShort(exception_data.handler_pc);
436             out.writeShort(exception_data.catch_type);
437         }
438 
439         @Override
visitCompilationID(CompilationID_attribute attr, ClassOutputStream out)440         public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) {
441             out.writeShort(attr.compilationID_index);
442             return null;
443         }
444 
445         @Override
visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out)446         public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) {
447             out.writeShort(attr.constantvalue_index);
448             return null;
449         }
450 
451         @Override
visitDeprecated(Deprecated_attribute attr, ClassOutputStream out)452         public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) {
453             return null;
454         }
455 
456         @Override
visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out)457         public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) {
458             out.writeShort(attr.class_index);
459             out.writeShort(attr.method_index);
460             return null;
461         }
462 
463         @Override
visitExceptions(Exceptions_attribute attr, ClassOutputStream out)464         public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) {
465             out.writeShort(attr.exception_index_table.length);
466             for (int i: attr.exception_index_table)
467                 out.writeShort(i);
468             return null;
469         }
470 
471         @Override
visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out)472         public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) {
473             out.writeShort(attr.classes.length);
474             for (InnerClasses_attribute.Info info: attr.classes)
475                 writeInnerClassesInfo(info, out);
476             return null;
477         }
478 
writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out)479         protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) {
480             out.writeShort(info.inner_class_info_index);
481             out.writeShort(info.outer_class_info_index);
482             out.writeShort(info.inner_name_index);
483             writeAccessFlags(info.inner_class_access_flags, out);
484         }
485 
486         @Override
visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out)487         public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) {
488             out.writeShort(attr.line_number_table.length);
489             for (LineNumberTable_attribute.Entry e: attr.line_number_table)
490                 writeLineNumberTableEntry(e, out);
491             return null;
492         }
493 
writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out)494         protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) {
495             out.writeShort(entry.start_pc);
496             out.writeShort(entry.line_number);
497         }
498 
499         @Override
visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out)500         public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) {
501             out.writeShort(attr.local_variable_table.length);
502             for (LocalVariableTable_attribute.Entry e: attr.local_variable_table)
503                 writeLocalVariableTableEntry(e, out);
504             return null;
505         }
506 
writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out)507         protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) {
508             out.writeShort(entry.start_pc);
509             out.writeShort(entry.length);
510             out.writeShort(entry.name_index);
511             out.writeShort(entry.descriptor_index);
512             out.writeShort(entry.index);
513         }
514 
515         @Override
visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out)516         public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) {
517             out.writeShort(attr.local_variable_table.length);
518             for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table)
519                 writeLocalVariableTypeTableEntry(e, out);
520             return null;
521         }
522 
writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out)523         protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) {
524             out.writeShort(entry.start_pc);
525             out.writeShort(entry.length);
526             out.writeShort(entry.name_index);
527             out.writeShort(entry.signature_index);
528             out.writeShort(entry.index);
529         }
530 
531         @Override
visitNestHost(NestHost_attribute attr, ClassOutputStream out)532         public Void visitNestHost(NestHost_attribute attr, ClassOutputStream out) {
533             out.writeShort(attr.top_index);
534             return null;
535         }
536 
537         @Override
visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out)538         public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) {
539             out.writeByte(attr.method_parameter_table.length);
540             for (MethodParameters_attribute.Entry e : attr.method_parameter_table) {
541                 out.writeShort(e.name_index);
542                 out.writeShort(e.flags);
543             }
544             return null;
545         }
546 
547         @Override
visitModule(Module_attribute attr, ClassOutputStream out)548         public Void visitModule(Module_attribute attr, ClassOutputStream out) {
549             out.writeShort(attr.module_name);
550             out.writeShort(attr.module_flags);
551             out.writeShort(attr.module_version_index);
552 
553             out.writeShort(attr.requires.length);
554             for (Module_attribute.RequiresEntry e: attr.requires) {
555                 out.writeShort(e.requires_index);
556                 out.writeShort(e.requires_flags);
557                 out.writeShort(e.requires_version_index);
558             }
559 
560             out.writeShort(attr.exports.length);
561             for (Module_attribute.ExportsEntry e: attr.exports) {
562                 out.writeShort(e.exports_index);
563                 out.writeShort(e.exports_flags);
564                 out.writeShort(e.exports_to_index.length);
565                 for (int index: e.exports_to_index)
566                     out.writeShort(index);
567             }
568 
569             out.writeShort(attr.opens.length);
570             for (Module_attribute.OpensEntry e: attr.opens) {
571                 out.writeShort(e.opens_index);
572                 out.writeShort(e.opens_flags);
573                 out.writeShort(e.opens_to_index.length);
574                 for (int index: e.opens_to_index)
575                     out.writeShort(index);
576             }
577 
578             out.writeShort(attr.uses_index.length);
579             for (int index: attr.uses_index) {
580                 out.writeShort(index);
581             }
582 
583             out.writeShort(attr.provides.length);
584             for (Module_attribute.ProvidesEntry e: attr.provides) {
585                 out.writeShort(e.provides_index);
586                 out.writeShort(e.with_count);
587                 for (int with : e.with_index) {
588                     out.writeShort(with);
589                 }
590             }
591 
592             return null;
593         }
594 
595         @Override
visitModuleHashes(ModuleHashes_attribute attr, ClassOutputStream out)596         public Void visitModuleHashes(ModuleHashes_attribute attr, ClassOutputStream out) {
597             out.writeShort(attr.algorithm_index);
598             out.writeShort(attr.hashes_table.length);
599             for (ModuleHashes_attribute.Entry e: attr.hashes_table) {
600                 out.writeShort(e.module_name_index);
601                 out.writeShort(e.hash.length);
602                 for (byte b: e.hash) {
603                     out.writeByte(b);
604                 }
605             }
606             return null;
607         }
608 
609         @Override
visitModuleMainClass(ModuleMainClass_attribute attr, ClassOutputStream out)610         public Void visitModuleMainClass(ModuleMainClass_attribute attr, ClassOutputStream out) {
611             out.writeShort(attr.main_class_index);
612             return null;
613         }
614 
615         @Override
visitModulePackages(ModulePackages_attribute attr, ClassOutputStream out)616         public Void visitModulePackages(ModulePackages_attribute attr, ClassOutputStream out) {
617             out.writeShort(attr.packages_count);
618             for (int i: attr.packages_index)
619                 out.writeShort(i);
620             return null;
621         }
622 
623         @Override
visitModuleResolution(ModuleResolution_attribute attr, ClassOutputStream out)624         public Void visitModuleResolution(ModuleResolution_attribute attr, ClassOutputStream out) {
625             out.writeShort(attr.resolution_flags);
626             return null;
627         }
628 
629         @Override
visitModuleTarget(ModuleTarget_attribute attr, ClassOutputStream out)630         public Void visitModuleTarget(ModuleTarget_attribute attr, ClassOutputStream out) {
631             out.writeShort(attr.target_platform_index);
632             return null;
633         }
634 
635         @Override
visitNestMembers(NestMembers_attribute attr, ClassOutputStream out)636         public Void visitNestMembers(NestMembers_attribute attr, ClassOutputStream out) {
637             out.writeShort(attr.members_indexes.length);
638             for (int i : attr.members_indexes) {
639                 out.writeShort(i);
640             }
641             return null;
642         }
643 
644         @Override
visitRecord(Record_attribute attr, ClassOutputStream out)645         public Void visitRecord(Record_attribute attr, ClassOutputStream out) {
646             out.writeShort(attr.component_count);
647             for (Record_attribute.ComponentInfo info: attr.component_info_arr) {
648                 out.writeShort(info.name_index);
649                 out.writeShort(info.descriptor.index);
650                 int size = info.attributes.size();
651                 out.writeShort(size);
652                 for (Attribute componentAttr: info.attributes)
653                     write(componentAttr, out);
654             }
655             return null;
656         }
657 
658         @Override
visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out)659         public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) {
660             annotationWriter.write(attr.annotations, out);
661             return null;
662         }
663 
664         @Override
visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out)665         public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
666             out.writeByte(attr.parameter_annotations.length);
667             for (Annotation[] annos: attr.parameter_annotations)
668                 annotationWriter.write(annos, out);
669             return null;
670         }
671 
672         @Override
visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out)673         public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) {
674             annotationWriter.write(attr.annotations, out);
675             return null;
676         }
677 
678         @Override
visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out)679         public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {
680             annotationWriter.write(attr.annotations, out);
681             return null;
682         }
683 
684         @Override
visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out)685         public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
686             out.writeByte(attr.parameter_annotations.length);
687             for (Annotation[] annos: attr.parameter_annotations)
688                 annotationWriter.write(annos, out);
689             return null;
690         }
691 
692         @Override
visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out)693         public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) {
694             annotationWriter.write(attr.annotations, out);
695             return null;
696         }
697 
698         @Override
visitPermittedSubclasses(PermittedSubclasses_attribute attr, ClassOutputStream out)699         public Void visitPermittedSubclasses(PermittedSubclasses_attribute attr, ClassOutputStream out) {
700             int n = attr.subtypes.length;
701             out.writeShort(n);
702             for (int i = 0 ; i < n ; i++) {
703                 out.writeShort(attr.subtypes[i]);
704             }
705             return null;
706         }
707 
708         @Override
visitSignature(Signature_attribute attr, ClassOutputStream out)709         public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {
710             out.writeShort(attr.signature_index);
711             return null;
712         }
713 
714         @Override
visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out)715         public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) {
716             out.write(attr.debug_extension, 0, attr.debug_extension.length);
717             return null;
718         }
719 
720         @Override
visitSourceFile(SourceFile_attribute attr, ClassOutputStream out)721         public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) {
722             out.writeShort(attr.sourcefile_index);
723             return null;
724         }
725 
726         @Override
visitSourceID(SourceID_attribute attr, ClassOutputStream out)727         public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) {
728             out.writeShort(attr.sourceID_index);
729             return null;
730         }
731 
732         @Override
visitStackMap(StackMap_attribute attr, ClassOutputStream out)733         public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) {
734             if (stackMapWriter == null)
735                 stackMapWriter = new StackMapTableWriter();
736 
737             out.writeShort(attr.entries.length);
738             for (stack_map_frame f: attr.entries)
739                 stackMapWriter.write(f, out);
740             return null;
741         }
742 
743         @Override
visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out)744         public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) {
745             if (stackMapWriter == null)
746                 stackMapWriter = new StackMapTableWriter();
747 
748             out.writeShort(attr.entries.length);
749             for (stack_map_frame f: attr.entries)
750                 stackMapWriter.write(f, out);
751             return null;
752         }
753 
754         @Override
visitSynthetic(Synthetic_attribute attr, ClassOutputStream out)755         public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) {
756             return null;
757         }
758 
writeAccessFlags(AccessFlags flags, ClassOutputStream p)759         protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) {
760             sharedOut.writeShort(flags.flags);
761         }
762 
763         protected StackMapTableWriter stackMapWriter;
764     }
765 
766     /**
767      * Writer for the frames of StackMap and StackMapTable attributes.
768      */
769     protected static class StackMapTableWriter
770             implements stack_map_frame.Visitor<Void,ClassOutputStream> {
771 
write(stack_map_frame frame, ClassOutputStream out)772         public void write(stack_map_frame frame, ClassOutputStream out) {
773             out.write(frame.frame_type);
774             frame.accept(this, out);
775         }
776 
777         @Override
visit_same_frame(same_frame frame, ClassOutputStream p)778         public Void visit_same_frame(same_frame frame, ClassOutputStream p) {
779             return null;
780         }
781 
782         @Override
visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out)783         public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) {
784             writeVerificationTypeInfo(frame.stack[0], out);
785             return null;
786         }
787 
788         @Override
visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out)789         public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) {
790             out.writeShort(frame.offset_delta);
791             writeVerificationTypeInfo(frame.stack[0], out);
792             return null;
793         }
794 
795         @Override
visit_chop_frame(chop_frame frame, ClassOutputStream out)796         public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) {
797             out.writeShort(frame.offset_delta);
798             return null;
799         }
800 
801         @Override
visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out)802         public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) {
803             out.writeShort(frame.offset_delta);
804             return null;
805         }
806 
807         @Override
visit_append_frame(append_frame frame, ClassOutputStream out)808         public Void visit_append_frame(append_frame frame, ClassOutputStream out) {
809             out.writeShort(frame.offset_delta);
810             for (verification_type_info l: frame.locals)
811                 writeVerificationTypeInfo(l, out);
812             return null;
813         }
814 
815         @Override
visit_full_frame(full_frame frame, ClassOutputStream out)816         public Void visit_full_frame(full_frame frame, ClassOutputStream out) {
817             out.writeShort(frame.offset_delta);
818             out.writeShort(frame.locals.length);
819             for (verification_type_info l: frame.locals)
820                 writeVerificationTypeInfo(l, out);
821             out.writeShort(frame.stack.length);
822             for (verification_type_info s: frame.stack)
823                 writeVerificationTypeInfo(s, out);
824             return null;
825         }
826 
writeVerificationTypeInfo(verification_type_info info, ClassOutputStream out)827         protected void writeVerificationTypeInfo(verification_type_info info,
828                 ClassOutputStream out)  {
829             out.write(info.tag);
830             switch (info.tag) {
831             case ITEM_Top:
832             case ITEM_Integer:
833             case ITEM_Float:
834             case ITEM_Long:
835             case ITEM_Double:
836             case ITEM_Null:
837             case ITEM_UninitializedThis:
838                 break;
839 
840             case ITEM_Object:
841                 Object_variable_info o = (Object_variable_info) info;
842                 out.writeShort(o.cpool_index);
843                 break;
844 
845             case ITEM_Uninitialized:
846                 Uninitialized_variable_info u = (Uninitialized_variable_info) info;
847                 out.writeShort(u.offset);
848                 break;
849 
850             default:
851                 throw new Error();
852             }
853         }
854     }
855 
856     /**
857      * Writer for annotations and the values they contain.
858      */
859     protected static class AnnotationWriter
860             implements Annotation.element_value.Visitor<Void,ClassOutputStream> {
write(Annotation[] annos, ClassOutputStream out)861         public void write(Annotation[] annos, ClassOutputStream out) {
862             out.writeShort(annos.length);
863             for (Annotation anno: annos)
864                 write(anno, out);
865         }
866 
write(TypeAnnotation[] annos, ClassOutputStream out)867         public void write(TypeAnnotation[] annos, ClassOutputStream out) {
868             out.writeShort(annos.length);
869             for (TypeAnnotation anno: annos)
870                 write(anno, out);
871         }
872 
write(Annotation anno, ClassOutputStream out)873         public void write(Annotation anno, ClassOutputStream out) {
874             out.writeShort(anno.type_index);
875             out.writeShort(anno.element_value_pairs.length);
876             for (element_value_pair p: anno.element_value_pairs)
877                 write(p, out);
878         }
879 
write(TypeAnnotation anno, ClassOutputStream out)880         public void write(TypeAnnotation anno, ClassOutputStream out) {
881             write(anno.position, out);
882             write(anno.annotation, out);
883         }
884 
write(element_value_pair pair, ClassOutputStream out)885         public void write(element_value_pair pair, ClassOutputStream out) {
886             out.writeShort(pair.element_name_index);
887             write(pair.value, out);
888         }
889 
write(element_value ev, ClassOutputStream out)890         public void write(element_value ev, ClassOutputStream out) {
891             out.writeByte(ev.tag);
892             ev.accept(this, out);
893         }
894 
895         @Override
visitPrimitive(Primitive_element_value ev, ClassOutputStream out)896         public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) {
897             out.writeShort(ev.const_value_index);
898             return null;
899         }
900 
901         @Override
visitEnum(Enum_element_value ev, ClassOutputStream out)902         public Void visitEnum(Enum_element_value ev, ClassOutputStream out) {
903             out.writeShort(ev.type_name_index);
904             out.writeShort(ev.const_name_index);
905             return null;
906         }
907 
908         @Override
visitClass(Class_element_value ev, ClassOutputStream out)909         public Void visitClass(Class_element_value ev, ClassOutputStream out) {
910             out.writeShort(ev.class_info_index);
911             return null;
912         }
913 
914         @Override
visitAnnotation(Annotation_element_value ev, ClassOutputStream out)915         public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) {
916             write(ev.annotation_value, out);
917             return null;
918         }
919 
920         @Override
visitArray(Array_element_value ev, ClassOutputStream out)921         public Void visitArray(Array_element_value ev, ClassOutputStream out) {
922             out.writeShort(ev.num_values);
923             for (element_value v: ev.values)
924                 write(v, out);
925             return null;
926         }
927 
928         // TODO: Move this to TypeAnnotation to be closer with similar logic?
write(TypeAnnotation.Position p, ClassOutputStream out)929         private void write(TypeAnnotation.Position p, ClassOutputStream out) {
930             out.writeByte(p.type.targetTypeValue());
931             switch (p.type) {
932             // instanceof
933             case INSTANCEOF:
934             // new expression
935             case NEW:
936             // constructor/method reference receiver
937             case CONSTRUCTOR_REFERENCE:
938             case METHOD_REFERENCE:
939                 out.writeShort(p.offset);
940                 break;
941             // local variable
942             case LOCAL_VARIABLE:
943             // resource variable
944             case RESOURCE_VARIABLE:
945                 int table_length = p.lvarOffset.length;
946                 out.writeShort(table_length);
947                 for (int i = 0; i < table_length; ++i) {
948                     out.writeShort(1);  // for table length
949                     out.writeShort(p.lvarOffset[i]);
950                     out.writeShort(p.lvarLength[i]);
951                     out.writeShort(p.lvarIndex[i]);
952                 }
953                 break;
954             // exception parameter
955             case EXCEPTION_PARAMETER:
956                 out.writeShort(p.exception_index);
957                 break;
958             // method receiver
959             case METHOD_RECEIVER:
960                 // Do nothing
961                 break;
962             // type parameters
963             case CLASS_TYPE_PARAMETER:
964             case METHOD_TYPE_PARAMETER:
965                 out.writeByte(p.parameter_index);
966                 break;
967             // type parameters bounds
968             case CLASS_TYPE_PARAMETER_BOUND:
969             case METHOD_TYPE_PARAMETER_BOUND:
970                 out.writeByte(p.parameter_index);
971                 out.writeByte(p.bound_index);
972                 break;
973             // class extends or implements clause
974             case CLASS_EXTENDS:
975                 out.writeShort(p.type_index);
976                 break;
977             // throws
978             case THROWS:
979                 out.writeShort(p.type_index);
980                 break;
981             // method parameter
982             case METHOD_FORMAL_PARAMETER:
983                 out.writeByte(p.parameter_index);
984                 break;
985             // type cast
986             case CAST:
987             // method/constructor/reference type argument
988             case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
989             case METHOD_INVOCATION_TYPE_ARGUMENT:
990             case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
991             case METHOD_REFERENCE_TYPE_ARGUMENT:
992                 out.writeShort(p.offset);
993                 out.writeByte(p.type_index);
994                 break;
995             // We don't need to worry about these
996             case METHOD_RETURN:
997             case FIELD:
998                 break;
999             case UNKNOWN:
1000                 throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!");
1001             default:
1002                 throw new AssertionError("ClassWriter: Unknown target type for position: " + p);
1003             }
1004 
1005             { // Append location data for generics/arrays.
1006                 // TODO: check for overrun?
1007                 out.writeByte((byte)p.location.size());
1008                 for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location))
1009                     out.writeByte((byte)i);
1010             }
1011         }
1012     }
1013 }
1014