Tue, 19 May 2009 11:50:54 -0700
6824493: experimental support for additional info for instructions
Reviewed-by: mcimadamore
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 */
26 package com.sun.tools.classfile;
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;
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.*;
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 }
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 }
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 }
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 }
87 protected void writeHeader() {
88 out.writeInt(classFile.magic);
89 out.writeShort(classFile.minor_version);
90 out.writeShort(classFile.major_version);
91 }
93 protected void writeAccessFlags(AccessFlags flags) {
94 out.writeShort(flags.flags);
95 }
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 }
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 }
113 protected void writeDescriptor(Descriptor d) {
114 out.writeShort(d.index);
115 }
117 protected void writeConstantPool() {
118 ConstantPool pool = classFile.constant_pool;
119 int size = pool.size();
120 out.writeShort(size);
121 for (CPInfo cpInfo: pool.entries())
122 constantPoolWriter.write(cpInfo, out);
123 }
125 protected void writeFields() throws IOException {
126 Field[] fields = classFile.fields;
127 out.writeShort(fields.length);
128 for (Field f: fields)
129 writeField(f);
130 }
132 protected void writeField(Field f) throws IOException {
133 writeAccessFlags(f.access_flags);
134 out.writeShort(f.name_index);
135 writeDescriptor(f.descriptor);
136 writeAttributes(f.attributes);
137 }
139 protected void writeMethods() throws IOException {
140 Method[] methods = classFile.methods;
141 out.writeShort(methods.length);
142 for (Method m: methods) {
143 writeMethod(m);
144 }
145 }
147 protected void writeMethod(Method m) throws IOException {
148 writeAccessFlags(m.access_flags);
149 out.writeShort(m.name_index);
150 writeDescriptor(m.descriptor);
151 writeAttributes(m.attributes);
152 }
154 protected ClassFile classFile;
155 protected ClassOutputStream out;
156 protected AttributeWriter attributeWriter;
157 protected ConstantPoolWriter constantPoolWriter;
159 /**
160 * Subtype of ByteArrayOutputStream with the convenience methods of
161 * a DataOutputStream. Since ByteArrayOutputStream does not throw
162 * IOException, there are no exceptions from the additional
163 * convenience methods either,
164 */
165 protected static class ClassOutputStream extends ByteArrayOutputStream {
166 public ClassOutputStream() {
167 d = new DataOutputStream(this);
168 }
170 public void writeByte(int value) {
171 try {
172 d.writeByte(value);
173 } catch (IOException ignore) {
174 }
175 }
177 public void writeShort(int value) {
178 try {
179 d.writeShort(value);
180 } catch (IOException ignore) {
181 }
182 }
184 public void writeInt(int value) {
185 try {
186 d.writeInt(value);
187 } catch (IOException ignore) {
188 }
189 }
191 public void writeLong(long value) {
192 try {
193 d.writeLong(value);
194 } catch (IOException ignore) {
195 }
196 }
198 public void writeFloat(float value) {
199 try {
200 d.writeFloat(value);
201 } catch (IOException ignore) {
202 }
203 }
205 public void writeDouble(double value) {
206 try {
207 d.writeDouble(value);
208 } catch (IOException ignore) {
209 }
210 }
212 public void writeUTF(String value) {
213 try {
214 d.writeUTF(value);
215 } catch (IOException ignore) {
216 }
217 }
219 public void writeTo(ClassOutputStream s) {
220 try {
221 super.writeTo(s);
222 } catch (IOException ignore) {
223 }
224 }
226 private DataOutputStream d;
227 }
229 /**
230 * Writer for the entries in the constant pool.
231 */
232 protected static class ConstantPoolWriter
233 implements ConstantPool.Visitor<Integer,ClassOutputStream> {
234 protected int write(CPInfo info, ClassOutputStream out) {
235 out.writeByte(info.getTag());
236 return info.accept(this, out);
237 }
239 public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) {
240 out.writeShort(info.name_index);
241 return 1;
242 }
244 public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) {
245 out.writeDouble(info.value);
246 return 2;
247 }
249 public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) {
250 writeRef(info, out);
251 return 1;
252 }
254 public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) {
255 out.writeFloat(info.value);
256 return 1;
257 }
259 public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) {
260 out.writeInt(info.value);
261 return 1;
262 }
264 public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) {
265 writeRef(info, out);
266 return 1;
267 }
269 public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) {
270 out.writeLong(info.value);
271 return 2;
272 }
274 public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) {
275 out.writeShort(info.name_index);
276 out.writeShort(info.type_index);
277 return 1;
278 }
280 public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) {
281 return writeRef(info, out);
282 }
284 public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) {
285 out.writeShort(info.string_index);
286 return 1;
287 }
289 public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) {
290 out.writeUTF(info.value);
291 return 1;
292 }
294 protected Integer writeRef(CPRefInfo info, ClassOutputStream out) {
295 out.writeShort(info.class_index);
296 out.writeShort(info.name_and_type_index);
297 return 1;
298 }
299 }
301 /**
302 * Writer for the different types of attribute.
303 */
304 protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> {
305 public void write(Attributes attributes, ClassOutputStream out) {
306 int size = attributes.size();
307 out.writeShort(size);
308 for (Attribute a: attributes)
309 write(a, out);
310 }
312 // Note: due to the use of shared resources, this method is not reentrant.
313 public void write(Attribute attr, ClassOutputStream out) {
314 out.writeShort(attr.attribute_name_index);
315 sharedOut.reset();
316 attr.accept(this, sharedOut);
317 out.writeInt(sharedOut.size());
318 sharedOut.writeTo(out);
319 }
321 protected ClassOutputStream sharedOut = new ClassOutputStream();
322 protected AnnotationWriter annotationWriter = new AnnotationWriter();
324 public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) {
325 out.write(attr.info, 0, attr.info.length);
326 return null;
327 }
329 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) {
330 annotationWriter.write(attr.default_value, out);
331 return null;
332 }
334 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) {
335 out.writeShort(attr.character_range_table.length);
336 for (CharacterRangeTable_attribute.Entry e: attr.character_range_table)
337 writeCharacterRangeTableEntry(e, out);
338 return null;
339 }
341 protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) {
342 out.writeShort(entry.start_pc);
343 out.writeShort(entry.end_pc);
344 out.writeInt(entry.character_range_start);
345 out.writeInt(entry.character_range_end);
346 out.writeShort(entry.flags);
347 }
349 public Void visitCode(Code_attribute attr, ClassOutputStream out) {
350 out.writeShort(attr.max_stack);
351 out.writeShort(attr.max_locals);
352 out.writeInt(attr.code.length);
353 out.write(attr.code, 0, attr.code.length);
354 out.writeShort(attr.exception_table.length);
355 for (Code_attribute.Exception_data e: attr.exception_table)
356 writeExceptionTableEntry(e, out);
357 new AttributeWriter().write(attr.attributes, out);
358 return null;
359 }
361 protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) {
362 out.writeShort(exception_data.start_pc);
363 out.writeShort(exception_data.end_pc);
364 out.writeShort(exception_data.handler_pc);
365 out.writeShort(exception_data.catch_type);
366 }
368 public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) {
369 out.writeShort(attr.compilationID_index);
370 return null;
371 }
373 public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) {
374 out.writeShort(attr.constantvalue_index);
375 return null;
376 }
378 public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) {
379 return null;
380 }
382 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) {
383 out.writeShort(attr.class_index);
384 out.writeShort(attr.method_index);
385 return null;
386 }
388 public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) {
389 out.writeShort(attr.exception_index_table.length);
390 for (int i: attr.exception_index_table)
391 out.writeShort(i);
392 return null;
393 }
395 public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) {
396 out.writeShort(attr.classes.length);
397 for (InnerClasses_attribute.Info info: attr.classes)
398 writeInnerClassesInfo(info, out);
399 return null;
400 }
402 protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) {
403 out.writeShort(info.inner_class_info_index);
404 out.writeShort(info.outer_class_info_index);
405 out.writeShort(info.inner_name_index);
406 writeAccessFlags(info.inner_class_access_flags, out);
407 }
409 public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) {
410 out.writeShort(attr.line_number_table.length);
411 for (LineNumberTable_attribute.Entry e: attr.line_number_table)
412 writeLineNumberTableEntry(e, out);
413 return null;
414 }
416 protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) {
417 out.writeShort(entry.start_pc);
418 out.writeShort(entry.line_number);
419 }
421 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) {
422 out.writeShort(attr.local_variable_table.length);
423 for (LocalVariableTable_attribute.Entry e: attr.local_variable_table)
424 writeLocalVariableTableEntry(e, out);
425 return null;
426 }
428 protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) {
429 out.writeShort(entry.start_pc);
430 out.writeShort(entry.length);
431 out.writeShort(entry.name_index);
432 out.writeShort(entry.descriptor_index);
433 out.writeShort(entry.index);
434 }
436 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) {
437 out.writeByte(attr.local_variable_table.length);
438 for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table)
439 writeLocalVariableTypeTableEntry(e, out);
440 return null;
441 }
443 protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) {
444 out.writeShort(entry.start_pc);
445 out.writeShort(entry.length);
446 out.writeShort(entry.name_index);
447 out.writeShort(entry.signature_index);
448 out.writeShort(entry.index);
449 }
451 public Void visitModule(Module_attribute attr, ClassOutputStream out) {
452 out.writeShort(attr.module_name);
453 return null;
454 }
456 public Void visitModuleExportTable(ModuleExportTable_attribute attr, ClassOutputStream out) {
457 out.writeShort(attr.export_type_table.length);
458 for (int i: attr.export_type_table)
459 out.writeShort(i);
460 return null;
461 }
463 public Void visitModuleMemberTable(ModuleMemberTable_attribute attr, ClassOutputStream out) {
464 out.writeShort(attr.package_member_table.length);
465 for (int i: attr.package_member_table)
466 out.writeShort(i);
467 return null;
468 }
470 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {
471 annotationWriter.write(attr.annotations, out);
472 return null;
473 }
475 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) {
476 annotationWriter.write(attr.annotations, out);
477 return null;
478 }
480 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
481 out.writeByte(attr.parameter_annotations.length);
482 for (Annotation[] annos: attr.parameter_annotations)
483 annotationWriter.write(annos, out);
484 return null;
485 }
487 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
488 out.writeByte(attr.parameter_annotations.length);
489 for (Annotation[] annos: attr.parameter_annotations)
490 annotationWriter.write(annos, out);
491 return null;
492 }
494 public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {
495 out.writeShort(attr.signature_index);
496 return null;
497 }
499 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) {
500 out.write(attr.debug_extension, 0, attr.debug_extension.length);
501 return null;
502 }
504 public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) {
505 out.writeShort(attr.sourcefile_index);
506 return null;
507 }
509 public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) {
510 out.writeShort(attr.sourceID_index);
511 return null;
512 }
514 public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) {
515 if (stackMapWriter == null)
516 stackMapWriter = new StackMapTableWriter();
518 out.writeShort(attr.entries.length);
519 for (stack_map_frame f: attr.entries)
520 stackMapWriter.write(f, out);
521 return null;
522 }
524 public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) {
525 if (stackMapWriter == null)
526 stackMapWriter = new StackMapTableWriter();
528 out.writeShort(attr.entries.length);
529 for (stack_map_frame f: attr.entries)
530 stackMapWriter.write(f, out);
531 return null;
532 }
534 public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) {
535 return null;
536 }
538 protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) {
539 sharedOut.writeShort(flags.flags);
540 }
542 protected StackMapTableWriter stackMapWriter;
543 }
545 /**
546 * Writer for the frames of StackMap and StackMapTable attributes.
547 */
548 protected static class StackMapTableWriter
549 implements stack_map_frame.Visitor<Void,ClassOutputStream> {
551 public void write(stack_map_frame frame, ClassOutputStream out) {
552 out.write(frame.frame_type);
553 frame.accept(this, out);
554 }
556 public Void visit_same_frame(same_frame frame, ClassOutputStream p) {
557 return null;
558 }
560 public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) {
561 writeVerificationTypeInfo(frame.stack[0], out);
562 return null;
563 }
565 public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) {
566 out.writeShort(frame.offset_delta);
567 writeVerificationTypeInfo(frame.stack[0], out);
568 return null;
569 }
571 public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) {
572 out.writeShort(frame.offset_delta);
573 return null;
574 }
576 public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) {
577 out.writeShort(frame.offset_delta);
578 return null;
579 }
581 public Void visit_append_frame(append_frame frame, ClassOutputStream out) {
582 out.writeShort(frame.offset_delta);
583 for (verification_type_info l: frame.locals)
584 writeVerificationTypeInfo(l, out);
585 return null;
586 }
588 public Void visit_full_frame(full_frame frame, ClassOutputStream out) {
589 out.writeShort(frame.offset_delta);
590 out.writeShort(frame.locals.length);
591 for (verification_type_info l: frame.locals)
592 writeVerificationTypeInfo(l, out);
593 out.writeShort(frame.stack.length);
594 for (verification_type_info s: frame.stack)
595 writeVerificationTypeInfo(s, out);
596 return null;
597 }
599 protected void writeVerificationTypeInfo(verification_type_info info,
600 ClassOutputStream out) {
601 out.write(info.tag);
602 switch (info.tag) {
603 case ITEM_Top:
604 case ITEM_Integer:
605 case ITEM_Float:
606 case ITEM_Long:
607 case ITEM_Double:
608 case ITEM_Null:
609 case ITEM_UninitializedThis:
610 break;
612 case ITEM_Object:
613 Object_variable_info o = (Object_variable_info) info;
614 out.writeShort(o.cpool_index);
615 break;
617 case ITEM_Uninitialized:
618 Uninitialized_variable_info u = (Uninitialized_variable_info) info;
619 out.writeShort(u.offset);
620 break;
622 default:
623 throw new Error();
624 }
625 }
626 }
628 /**
629 * Writer for annotations and the values they contain.
630 */
631 protected static class AnnotationWriter
632 implements Annotation.element_value.Visitor<Void,ClassOutputStream> {
633 public void write(Annotation[] annos, ClassOutputStream out) {
634 out.writeShort(annos.length);
635 for (Annotation anno: annos)
636 write(anno, out);
637 }
639 public void write(Annotation anno, ClassOutputStream out) {
640 out.writeShort(anno.type_index);
641 out.writeShort(anno.element_value_pairs.length);
642 for (element_value_pair p: anno.element_value_pairs)
643 write(p, out);
644 }
646 public void write(element_value_pair pair, ClassOutputStream out) {
647 out.writeShort(pair.element_name_index);
648 write(pair.value, out);
649 }
651 public void write(element_value ev, ClassOutputStream out) {
652 out.writeByte(ev.tag);
653 ev.accept(this, out);
654 }
656 public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) {
657 out.writeShort(ev.const_value_index);
658 return null;
659 }
661 public Void visitEnum(Enum_element_value ev, ClassOutputStream out) {
662 out.writeShort(ev.type_name_index);
663 out.writeShort(ev.const_name_index);
664 return null;
665 }
667 public Void visitClass(Class_element_value ev, ClassOutputStream out) {
668 out.writeShort(ev.class_info_index);
669 return null;
670 }
672 public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) {
673 write(ev.annotation_value, out);
674 return null;
675 }
677 public Void visitArray(Array_element_value ev, ClassOutputStream out) {
678 out.writeShort(ev.num_values);
679 for (element_value v: ev.values)
680 write(v, out);
681 return null;
682 }
683 }
684 }