src/share/classes/com/sun/tools/classfile/ClassWriter.java

changeset 46
7708bd6d800d
child 282
fc634a593812
equal deleted inserted replaced
42:f7e64b33d5a4 46:7708bd6d800d
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package com.sun.tools.classfile;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.DataOutputStream;
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.OutputStream;
34
35 import static com.sun.tools.classfile.Annotation.*;
36 import static com.sun.tools.classfile.ConstantPool.*;
37 import static com.sun.tools.classfile.StackMapTable_attribute.*;
38 import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*;
39
40 /**
41 * Write a ClassFile data structure to a file or stream.
42 *
43 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
44 * you write code that depends on this, you do so at your own risk.
45 * This code and its internal interfaces are subject to change or
46 * deletion without notice.</b>
47 */
48 public class ClassWriter {
49 public ClassWriter() {
50 attributeWriter = new AttributeWriter();
51 constantPoolWriter = new ConstantPoolWriter();
52 out = new ClassOutputStream();
53 }
54
55 /**
56 * Write a ClassFile data structure to a file.
57 */
58 public void write(ClassFile classFile, File f) throws IOException {
59 FileOutputStream f_out = new FileOutputStream(f);
60 try {
61 write(classFile, f_out);
62 } finally {
63 f_out.close();
64 }
65 }
66
67 /**
68 * Write a ClassFile data structure to a stream.
69 */
70 public void write(ClassFile classFile, OutputStream s) throws IOException {
71 this.classFile = classFile;
72 out.reset();
73 write();
74 out.writeTo(s);
75 }
76
77 protected void write() throws IOException {
78 writeHeader();
79 writeConstantPool();
80 writeAccessFlags(classFile.access_flags);
81 writeClassInfo();
82 writeFields();
83 writeMethods();
84 writeAttributes(classFile.attributes);
85 }
86
87 protected void writeHeader() {
88 out.writeInt(classFile.magic);
89 out.writeShort(classFile.minor_version);
90 out.writeShort(classFile.major_version);
91 }
92
93 protected void writeAccessFlags(AccessFlags flags) {
94 out.writeShort(flags.flags);
95 }
96
97 protected void writeAttributes(Attributes attributes) {
98 int size = attributes.size();
99 out.writeShort(size);
100 for (Attribute attr: attributes)
101 attributeWriter.write(attr, out);
102 }
103
104 protected void writeClassInfo() {
105 out.writeShort(classFile.this_class);
106 out.writeShort(classFile.super_class);
107 int[] interfaces = classFile.interfaces;
108 out.writeShort(interfaces.length);
109 for (int i: interfaces)
110 out.writeShort(i);
111 }
112
113 protected void writeDescriptor(Descriptor d) {
114 out.writeShort(d.index);
115 }
116
117 protected void writeConstantPool() {
118 ConstantPool pool = classFile.constant_pool;
119 int size = pool.size();
120 out.writeShort(size);
121 try {
122 for (int i = 1; i < size; ) {
123 i += constantPoolWriter.write(pool.get(i), out);
124 }
125 } catch (ConstantPoolException e) {
126 throw new Error(e); // ??
127 }
128 }
129
130 protected void writeFields() throws IOException {
131 Field[] fields = classFile.fields;
132 out.writeShort(fields.length);
133 for (Field f: fields)
134 writeField(f);
135 }
136
137 protected void writeField(Field f) throws IOException {
138 writeAccessFlags(f.access_flags);
139 out.writeShort(f.name_index);
140 writeDescriptor(f.descriptor);
141 writeAttributes(f.attributes);
142 }
143
144 protected void writeMethods() throws IOException {
145 Method[] methods = classFile.methods;
146 out.writeShort(methods.length);
147 for (Method m: methods) {
148 writeMethod(m);
149 }
150 }
151
152 protected void writeMethod(Method m) throws IOException {
153 writeAccessFlags(m.access_flags);
154 out.writeShort(m.name_index);
155 writeDescriptor(m.descriptor);
156 writeAttributes(m.attributes);
157 }
158
159 protected ClassFile classFile;
160 protected ClassOutputStream out;
161 protected AttributeWriter attributeWriter;
162 protected ConstantPoolWriter constantPoolWriter;
163
164 /**
165 * Subtype of ByteArrayOutputStream with the convenience methods of
166 * a DataOutputStream. Since ByteArrayOutputStream does not throw
167 * IOException, there are no exceptions from the additional
168 * convenience methods either,
169 */
170 protected static class ClassOutputStream extends ByteArrayOutputStream {
171 public ClassOutputStream() {
172 d = new DataOutputStream(this);
173 }
174
175 public void writeByte(int value) {
176 try {
177 d.writeByte(value);
178 } catch (IOException ignore) {
179 }
180 }
181
182 public void writeShort(int value) {
183 try {
184 d.writeShort(value);
185 } catch (IOException ignore) {
186 }
187 }
188
189 public void writeInt(int value) {
190 try {
191 d.writeInt(value);
192 } catch (IOException ignore) {
193 }
194 }
195
196 public void writeLong(long value) {
197 try {
198 d.writeLong(value);
199 } catch (IOException ignore) {
200 }
201 }
202
203 public void writeFloat(float value) {
204 try {
205 d.writeFloat(value);
206 } catch (IOException ignore) {
207 }
208 }
209
210 public void writeDouble(double value) {
211 try {
212 d.writeDouble(value);
213 } catch (IOException ignore) {
214 }
215 }
216
217 public void writeUTF(String value) {
218 try {
219 d.writeUTF(value);
220 } catch (IOException ignore) {
221 }
222 }
223
224 public void writeTo(ClassOutputStream s) {
225 try {
226 super.writeTo(s);
227 } catch (IOException ignore) {
228 }
229 }
230
231 private DataOutputStream d;
232 }
233
234 /**
235 * Writer for the entries in the constant pool.
236 */
237 protected static class ConstantPoolWriter
238 implements ConstantPool.Visitor<Integer,ClassOutputStream> {
239 protected int write(CPInfo info, ClassOutputStream out) {
240 out.writeByte(info.getTag());
241 return info.accept(this, out);
242 }
243
244 public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) {
245 out.writeShort(info.name_index);
246 return 1;
247 }
248
249 public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) {
250 out.writeDouble(info.value);
251 return 2;
252 }
253
254 public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) {
255 writeRef(info, out);
256 return 1;
257 }
258
259 public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) {
260 out.writeFloat(info.value);
261 return 1;
262 }
263
264 public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) {
265 out.writeInt(info.value);
266 return 1;
267 }
268
269 public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) {
270 writeRef(info, out);
271 return 1;
272 }
273
274 public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) {
275 out.writeLong(info.value);
276 return 2;
277 }
278
279 public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) {
280 out.writeShort(info.name_index);
281 out.writeShort(info.type_index);
282 return 1;
283 }
284
285 public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) {
286 return writeRef(info, out);
287 }
288
289 public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) {
290 out.writeShort(info.string_index);
291 return 1;
292 }
293
294 public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) {
295 out.writeUTF(info.value);
296 return 1;
297 }
298
299 protected Integer writeRef(CPRefInfo info, ClassOutputStream out) {
300 out.writeShort(info.class_index);
301 out.writeShort(info.name_and_type_index);
302 return 1;
303 }
304 }
305
306 /**
307 * Writer for the different types of attribute.
308 */
309 protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> {
310 public void write(Attributes attributes, ClassOutputStream out) {
311 int size = attributes.size();
312 out.writeShort(size);
313 for (Attribute a: attributes)
314 write(a, out);
315 }
316
317 // Note: due to the use of shared resources, this method is not reentrant.
318 public void write(Attribute attr, ClassOutputStream out) {
319 out.writeShort(attr.attribute_name_index);
320 sharedOut.reset();
321 attr.accept(this, sharedOut);
322 out.writeInt(sharedOut.size());
323 sharedOut.writeTo(out);
324 }
325
326 protected ClassOutputStream sharedOut = new ClassOutputStream();
327 protected AnnotationWriter annotationWriter = new AnnotationWriter();
328
329 public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) {
330 out.write(attr.info, 0, attr.info.length);
331 return null;
332 }
333
334 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) {
335 annotationWriter.write(attr.default_value, out);
336 return null;
337 }
338
339 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) {
340 out.writeShort(attr.character_range_table.length);
341 for (CharacterRangeTable_attribute.Entry e: attr.character_range_table)
342 writeCharacterRangeTableEntry(e, out);
343 return null;
344 }
345
346 protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) {
347 out.writeShort(entry.start_pc);
348 out.writeShort(entry.end_pc);
349 out.writeInt(entry.character_range_start);
350 out.writeInt(entry.character_range_end);
351 out.writeShort(entry.flags);
352 }
353
354 public Void visitCode(Code_attribute attr, ClassOutputStream out) {
355 out.writeShort(attr.max_stack);
356 out.writeShort(attr.max_locals);
357 out.writeInt(attr.code.length);
358 out.write(attr.code, 0, attr.code.length);
359 out.writeShort(attr.exception_table.length);
360 for (Code_attribute.Exception_data e: attr.exception_table)
361 writeExceptionTableEntry(e, out);
362 new AttributeWriter().write(attr.attributes, out);
363 return null;
364 }
365
366 protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) {
367 out.writeShort(exception_data.start_pc);
368 out.writeShort(exception_data.end_pc);
369 out.writeShort(exception_data.handler_pc);
370 out.writeShort(exception_data.catch_type);
371 }
372
373 public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) {
374 out.writeShort(attr.compilationID_index);
375 return null;
376 }
377
378 public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) {
379 out.writeShort(attr.constantvalue_index);
380 return null;
381 }
382
383 public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) {
384 return null;
385 }
386
387 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) {
388 out.writeShort(attr.class_index);
389 out.writeShort(attr.method_index);
390 return null;
391 }
392
393 public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) {
394 out.writeShort(attr.exception_index_table.length);
395 for (int i: attr.exception_index_table)
396 out.writeShort(i);
397 return null;
398 }
399
400 public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) {
401 out.writeShort(attr.classes.length);
402 for (InnerClasses_attribute.Info info: attr.classes)
403 writeInnerClassesInfo(info, out);
404 return null;
405 }
406
407 protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) {
408 out.writeShort(info.inner_class_info_index);
409 out.writeShort(info.outer_class_info_index);
410 out.writeShort(info.inner_name_index);
411 writeAccessFlags(info.inner_class_access_flags, out);
412 }
413
414 public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) {
415 out.writeShort(attr.line_number_table.length);
416 for (LineNumberTable_attribute.Entry e: attr.line_number_table)
417 writeLineNumberTableEntry(e, out);
418 return null;
419 }
420
421 protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) {
422 out.writeShort(entry.start_pc);
423 out.writeShort(entry.line_number);
424 }
425
426 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) {
427 out.writeShort(attr.local_variable_table.length);
428 for (LocalVariableTable_attribute.Entry e: attr.local_variable_table)
429 writeLocalVariableTableEntry(e, out);
430 return null;
431 }
432
433 protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) {
434 out.writeShort(entry.start_pc);
435 out.writeShort(entry.length);
436 out.writeShort(entry.name_index);
437 out.writeShort(entry.descriptor_index);
438 out.writeShort(entry.index);
439 }
440
441 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) {
442 out.writeByte(attr.local_variable_table.length);
443 for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table)
444 writeLocalVariableTypeTableEntry(e, out);
445 return null;
446 }
447
448 protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) {
449 out.writeShort(entry.start_pc);
450 out.writeShort(entry.length);
451 out.writeShort(entry.name_index);
452 out.writeShort(entry.signature_index);
453 out.writeShort(entry.index);
454 }
455
456 public Void visitModule(Module_attribute attr, ClassOutputStream out) {
457 out.writeShort(attr.module_name);
458 return null;
459 }
460
461 public Void visitModuleExportTable(ModuleExportTable_attribute attr, ClassOutputStream out) {
462 out.writeShort(attr.export_type_table.length);
463 for (int i: attr.export_type_table)
464 out.writeShort(i);
465 return null;
466 }
467
468 public Void visitModuleMemberTable(ModuleMemberTable_attribute attr, ClassOutputStream out) {
469 out.writeShort(attr.package_member_table.length);
470 for (int i: attr.package_member_table)
471 out.writeShort(i);
472 return null;
473 }
474
475 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {
476 annotationWriter.write(attr.annotations, out);
477 return null;
478 }
479
480 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) {
481 annotationWriter.write(attr.annotations, out);
482 return null;
483 }
484
485 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
486 out.writeByte(attr.parameter_annotations.length);
487 for (Annotation[] annos: attr.parameter_annotations)
488 annotationWriter.write(annos, out);
489 return null;
490 }
491
492 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
493 out.writeByte(attr.parameter_annotations.length);
494 for (Annotation[] annos: attr.parameter_annotations)
495 annotationWriter.write(annos, out);
496 return null;
497 }
498
499 public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {
500 out.writeShort(attr.signature_index);
501 return null;
502 }
503
504 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) {
505 out.write(attr.debug_extension, 0, attr.debug_extension.length);
506 return null;
507 }
508
509 public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) {
510 out.writeShort(attr.sourcefile_index);
511 return null;
512 }
513
514 public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) {
515 out.writeShort(attr.sourceID_index);
516 return null;
517 }
518
519 public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) {
520 if (stackMapWriter == null)
521 stackMapWriter = new StackMapTableWriter();
522
523 out.writeShort(attr.entries.length);
524 for (stack_map_frame f: attr.entries)
525 stackMapWriter.write(f, out);
526 return null;
527 }
528
529 public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) {
530 if (stackMapWriter == null)
531 stackMapWriter = new StackMapTableWriter();
532
533 out.writeShort(attr.entries.length);
534 for (stack_map_frame f: attr.entries)
535 stackMapWriter.write(f, out);
536 return null;
537 }
538
539 public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) {
540 return null;
541 }
542
543 protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) {
544 sharedOut.writeShort(flags.flags);
545 }
546
547 protected StackMapTableWriter stackMapWriter;
548 }
549
550 /**
551 * Writer for the frames of StackMap and StackMapTable attributes.
552 */
553 protected static class StackMapTableWriter
554 implements stack_map_frame.Visitor<Void,ClassOutputStream> {
555
556 public void write(stack_map_frame frame, ClassOutputStream out) {
557 out.write(frame.frame_type);
558 frame.accept(this, out);
559 }
560
561 public Void visit_same_frame(same_frame frame, ClassOutputStream p) {
562 return null;
563 }
564
565 public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) {
566 writeVerificationTypeInfo(frame.stack[0], out);
567 return null;
568 }
569
570 public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) {
571 out.writeShort(frame.offset_delta);
572 writeVerificationTypeInfo(frame.stack[0], out);
573 return null;
574 }
575
576 public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) {
577 out.writeShort(frame.offset_delta);
578 return null;
579 }
580
581 public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) {
582 out.writeShort(frame.offset_delta);
583 return null;
584 }
585
586 public Void visit_append_frame(append_frame frame, ClassOutputStream out) {
587 out.writeShort(frame.offset_delta);
588 for (verification_type_info l: frame.locals)
589 writeVerificationTypeInfo(l, out);
590 return null;
591 }
592
593 public Void visit_full_frame(full_frame frame, ClassOutputStream out) {
594 out.writeShort(frame.offset_delta);
595 out.writeShort(frame.locals.length);
596 for (verification_type_info l: frame.locals)
597 writeVerificationTypeInfo(l, out);
598 out.writeShort(frame.stack.length);
599 for (verification_type_info s: frame.stack)
600 writeVerificationTypeInfo(s, out);
601 return null;
602 }
603
604 protected void writeVerificationTypeInfo(verification_type_info info,
605 ClassOutputStream out) {
606 out.write(info.tag);
607 switch (info.tag) {
608 case ITEM_Top:
609 case ITEM_Integer:
610 case ITEM_Float:
611 case ITEM_Long:
612 case ITEM_Double:
613 case ITEM_Null:
614 case ITEM_UninitializedThis:
615 break;
616
617 case ITEM_Object:
618 Object_variable_info o = (Object_variable_info) info;
619 out.writeShort(o.cpool_index);
620 break;
621
622 case ITEM_Uninitialized:
623 Uninitialized_variable_info u = (Uninitialized_variable_info) info;
624 out.writeShort(u.offset);
625 break;
626
627 default:
628 throw new Error();
629 }
630 }
631 }
632
633 /**
634 * Writer for annotations and the values they contain.
635 */
636 protected static class AnnotationWriter
637 implements Annotation.element_value.Visitor<Void,ClassOutputStream> {
638 public void write(Annotation[] annos, ClassOutputStream out) {
639 out.writeShort(annos.length);
640 for (Annotation anno: annos)
641 write(anno, out);
642 }
643
644 public void write(Annotation anno, ClassOutputStream out) {
645 out.writeShort(anno.type_index);
646 out.writeShort(anno.element_value_pairs.length);
647 for (element_value_pair p: anno.element_value_pairs)
648 write(p, out);
649 }
650
651 public void write(element_value_pair pair, ClassOutputStream out) {
652 out.writeShort(pair.element_name_index);
653 write(pair.value, out);
654 }
655
656 public void write(element_value ev, ClassOutputStream out) {
657 out.writeByte(ev.tag);
658 ev.accept(this, out);
659 }
660
661 public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) {
662 out.writeShort(ev.const_value_index);
663 return null;
664 }
665
666 public Void visitEnum(Enum_element_value ev, ClassOutputStream out) {
667 out.writeShort(ev.type_name_index);
668 out.writeShort(ev.const_name_index);
669 return null;
670 }
671
672 public Void visitClass(Class_element_value ev, ClassOutputStream out) {
673 out.writeShort(ev.class_info_index);
674 return null;
675 }
676
677 public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) {
678 write(ev.annotation_value, out);
679 return null;
680 }
681
682 public Void visitArray(Array_element_value ev, ClassOutputStream out) {
683 out.writeShort(ev.num_values);
684 for (element_value v: ev.values)
685 write(v, out);
686 return null;
687 }
688 }
689 }

mercurial