Sat, 29 Dec 2012 17:33:17 -0800
8004727: Add compiler support for parameter reflection
Reviewed-by: jjg
Contributed-by: eric.mccorkle@oracle.com
2 /*
3 * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation. Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
27 package com.sun.tools.classfile;
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;
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.*;
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 {
50 public ClassWriter() {
51 attributeWriter = new AttributeWriter();
52 constantPoolWriter = new ConstantPoolWriter();
53 out = new ClassOutputStream();
54 }
56 /**
57 * Write a ClassFile data structure to a file.
58 */
59 public void write(ClassFile classFile, File f) throws IOException {
60 FileOutputStream f_out = new FileOutputStream(f);
61 try {
62 write(classFile, f_out);
63 } finally {
64 f_out.close();
65 }
66 }
68 /**
69 * Write a ClassFile data structure to a stream.
70 */
71 public void write(ClassFile classFile, OutputStream s) throws IOException {
72 this.classFile = classFile;
73 out.reset();
74 write();
75 out.writeTo(s);
76 }
78 protected void write() throws IOException {
79 writeHeader();
80 writeConstantPool();
81 writeAccessFlags(classFile.access_flags);
82 writeClassInfo();
83 writeFields();
84 writeMethods();
85 writeAttributes(classFile.attributes);
86 }
88 protected void writeHeader() {
89 out.writeInt(classFile.magic);
90 out.writeShort(classFile.minor_version);
91 out.writeShort(classFile.major_version);
92 }
94 protected void writeAccessFlags(AccessFlags flags) {
95 out.writeShort(flags.flags);
96 }
98 protected void writeAttributes(Attributes attributes) {
99 int size = attributes.size();
100 out.writeShort(size);
101 for (Attribute attr: attributes)
102 attributeWriter.write(attr, out);
103 }
105 protected void writeClassInfo() {
106 out.writeShort(classFile.this_class);
107 out.writeShort(classFile.super_class);
108 int[] interfaces = classFile.interfaces;
109 out.writeShort(interfaces.length);
110 for (int i: interfaces)
111 out.writeShort(i);
112 }
114 protected void writeDescriptor(Descriptor d) {
115 out.writeShort(d.index);
116 }
118 protected void writeConstantPool() {
119 ConstantPool pool = classFile.constant_pool;
120 int size = pool.size();
121 out.writeShort(size);
122 for (CPInfo cpInfo: pool.entries())
123 constantPoolWriter.write(cpInfo, out);
124 }
126 protected void writeFields() throws IOException {
127 Field[] fields = classFile.fields;
128 out.writeShort(fields.length);
129 for (Field f: fields)
130 writeField(f);
131 }
133 protected void writeField(Field f) throws IOException {
134 writeAccessFlags(f.access_flags);
135 out.writeShort(f.name_index);
136 writeDescriptor(f.descriptor);
137 writeAttributes(f.attributes);
138 }
140 protected void writeMethods() throws IOException {
141 Method[] methods = classFile.methods;
142 out.writeShort(methods.length);
143 for (Method m: methods) {
144 writeMethod(m);
145 }
146 }
148 protected void writeMethod(Method m) throws IOException {
149 writeAccessFlags(m.access_flags);
150 out.writeShort(m.name_index);
151 writeDescriptor(m.descriptor);
152 writeAttributes(m.attributes);
153 }
155 protected ClassFile classFile;
156 protected ClassOutputStream out;
157 protected AttributeWriter attributeWriter;
158 protected ConstantPoolWriter constantPoolWriter;
160 /**
161 * Subtype of ByteArrayOutputStream with the convenience methods of
162 * a DataOutputStream. Since ByteArrayOutputStream does not throw
163 * IOException, there are no exceptions from the additional
164 * convenience methods either,
165 */
166 protected static class ClassOutputStream extends ByteArrayOutputStream {
167 public ClassOutputStream() {
168 d = new DataOutputStream(this);
169 }
171 public void writeByte(int value) {
172 try {
173 d.writeByte(value);
174 } catch (IOException ignore) {
175 }
176 }
178 public void writeShort(int value) {
179 try {
180 d.writeShort(value);
181 } catch (IOException ignore) {
182 }
183 }
185 public void writeInt(int value) {
186 try {
187 d.writeInt(value);
188 } catch (IOException ignore) {
189 }
190 }
192 public void writeLong(long value) {
193 try {
194 d.writeLong(value);
195 } catch (IOException ignore) {
196 }
197 }
199 public void writeFloat(float value) {
200 try {
201 d.writeFloat(value);
202 } catch (IOException ignore) {
203 }
204 }
206 public void writeDouble(double value) {
207 try {
208 d.writeDouble(value);
209 } catch (IOException ignore) {
210 }
211 }
213 public void writeUTF(String value) {
214 try {
215 d.writeUTF(value);
216 } catch (IOException ignore) {
217 }
218 }
220 public void writeTo(ClassOutputStream s) {
221 try {
222 super.writeTo(s);
223 } catch (IOException ignore) {
224 }
225 }
227 private DataOutputStream d;
228 }
230 /**
231 * Writer for the entries in the constant pool.
232 */
233 protected static class ConstantPoolWriter
234 implements ConstantPool.Visitor<Integer,ClassOutputStream> {
235 protected int write(CPInfo info, ClassOutputStream out) {
236 out.writeByte(info.getTag());
237 return info.accept(this, out);
238 }
240 public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) {
241 out.writeShort(info.name_index);
242 return 1;
243 }
245 public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) {
246 out.writeDouble(info.value);
247 return 2;
248 }
250 public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) {
251 writeRef(info, out);
252 return 1;
253 }
255 public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) {
256 out.writeFloat(info.value);
257 return 1;
258 }
260 public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) {
261 out.writeInt(info.value);
262 return 1;
263 }
265 public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) {
266 writeRef(info, out);
267 return 1;
268 }
270 public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out) {
271 out.writeShort(info.bootstrap_method_attr_index);
272 out.writeShort(info.name_and_type_index);
273 return 1;
274 }
276 public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) {
277 out.writeLong(info.value);
278 return 2;
279 }
281 public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) {
282 out.writeShort(info.name_index);
283 out.writeShort(info.type_index);
284 return 1;
285 }
287 public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) {
288 out.writeByte(info.reference_kind.tag);
289 out.writeShort(info.reference_index);
290 return 1;
291 }
293 public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) {
294 out.writeShort(info.descriptor_index);
295 return 1;
296 }
298 public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) {
299 return writeRef(info, out);
300 }
302 public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) {
303 out.writeShort(info.string_index);
304 return 1;
305 }
307 public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) {
308 out.writeUTF(info.value);
309 return 1;
310 }
312 protected Integer writeRef(CPRefInfo info, ClassOutputStream out) {
313 out.writeShort(info.class_index);
314 out.writeShort(info.name_and_type_index);
315 return 1;
316 }
317 }
319 /**
320 * Writer for the different types of attribute.
321 */
322 protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> {
323 public void write(Attributes attributes, ClassOutputStream out) {
324 int size = attributes.size();
325 out.writeShort(size);
326 for (Attribute a: attributes)
327 write(a, out);
328 }
330 // Note: due to the use of shared resources, this method is not reentrant.
331 public void write(Attribute attr, ClassOutputStream out) {
332 out.writeShort(attr.attribute_name_index);
333 sharedOut.reset();
334 attr.accept(this, sharedOut);
335 out.writeInt(sharedOut.size());
336 sharedOut.writeTo(out);
337 }
339 protected ClassOutputStream sharedOut = new ClassOutputStream();
340 protected AnnotationWriter annotationWriter = new AnnotationWriter();
342 public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) {
343 out.write(attr.info, 0, attr.info.length);
344 return null;
345 }
347 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) {
348 annotationWriter.write(attr.default_value, out);
349 return null;
350 }
352 public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) {
353 out.writeShort(attr.bootstrap_method_specifiers.length);
354 for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) {
355 out.writeShort(bsm.bootstrap_method_ref);
356 int bsm_args_count = bsm.bootstrap_arguments.length;
357 out.writeShort(bsm_args_count);
358 for (int i : bsm.bootstrap_arguments) {
359 out.writeShort(i);
360 }
361 }
362 return null;
363 }
365 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) {
366 out.writeShort(attr.character_range_table.length);
367 for (CharacterRangeTable_attribute.Entry e: attr.character_range_table)
368 writeCharacterRangeTableEntry(e, out);
369 return null;
370 }
372 protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) {
373 out.writeShort(entry.start_pc);
374 out.writeShort(entry.end_pc);
375 out.writeInt(entry.character_range_start);
376 out.writeInt(entry.character_range_end);
377 out.writeShort(entry.flags);
378 }
380 public Void visitCode(Code_attribute attr, ClassOutputStream out) {
381 out.writeShort(attr.max_stack);
382 out.writeShort(attr.max_locals);
383 out.writeInt(attr.code.length);
384 out.write(attr.code, 0, attr.code.length);
385 out.writeShort(attr.exception_table.length);
386 for (Code_attribute.Exception_data e: attr.exception_table)
387 writeExceptionTableEntry(e, out);
388 new AttributeWriter().write(attr.attributes, out);
389 return null;
390 }
392 protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) {
393 out.writeShort(exception_data.start_pc);
394 out.writeShort(exception_data.end_pc);
395 out.writeShort(exception_data.handler_pc);
396 out.writeShort(exception_data.catch_type);
397 }
399 public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) {
400 out.writeShort(attr.compilationID_index);
401 return null;
402 }
404 public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) {
405 out.writeShort(attr.constantvalue_index);
406 return null;
407 }
409 public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) {
410 return null;
411 }
413 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) {
414 out.writeShort(attr.class_index);
415 out.writeShort(attr.method_index);
416 return null;
417 }
419 public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) {
420 out.writeShort(attr.exception_index_table.length);
421 for (int i: attr.exception_index_table)
422 out.writeShort(i);
423 return null;
424 }
426 public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) {
427 out.writeShort(attr.classes.length);
428 for (InnerClasses_attribute.Info info: attr.classes)
429 writeInnerClassesInfo(info, out);
430 return null;
431 }
433 protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) {
434 out.writeShort(info.inner_class_info_index);
435 out.writeShort(info.outer_class_info_index);
436 out.writeShort(info.inner_name_index);
437 writeAccessFlags(info.inner_class_access_flags, out);
438 }
440 public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) {
441 out.writeShort(attr.line_number_table.length);
442 for (LineNumberTable_attribute.Entry e: attr.line_number_table)
443 writeLineNumberTableEntry(e, out);
444 return null;
445 }
447 protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) {
448 out.writeShort(entry.start_pc);
449 out.writeShort(entry.line_number);
450 }
452 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) {
453 out.writeShort(attr.local_variable_table.length);
454 for (LocalVariableTable_attribute.Entry e: attr.local_variable_table)
455 writeLocalVariableTableEntry(e, out);
456 return null;
457 }
459 protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) {
460 out.writeShort(entry.start_pc);
461 out.writeShort(entry.length);
462 out.writeShort(entry.name_index);
463 out.writeShort(entry.descriptor_index);
464 out.writeShort(entry.index);
465 }
467 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) {
468 out.writeShort(attr.local_variable_table.length);
469 for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table)
470 writeLocalVariableTypeTableEntry(e, out);
471 return null;
472 }
474 protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) {
475 out.writeShort(entry.start_pc);
476 out.writeShort(entry.length);
477 out.writeShort(entry.name_index);
478 out.writeShort(entry.signature_index);
479 out.writeShort(entry.index);
480 }
482 public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) {
483 out.writeByte(attr.method_parameter_table.length);
484 for (MethodParameters_attribute.Entry e : attr.method_parameter_table) {
485 out.writeShort(e.name_index);
486 out.writeInt(e.flags);
487 }
488 return null;
489 }
491 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {
492 annotationWriter.write(attr.annotations, out);
493 return null;
494 }
496 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) {
497 annotationWriter.write(attr.annotations, out);
498 return null;
499 }
501 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
502 out.writeByte(attr.parameter_annotations.length);
503 for (Annotation[] annos: attr.parameter_annotations)
504 annotationWriter.write(annos, out);
505 return null;
506 }
508 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
509 out.writeByte(attr.parameter_annotations.length);
510 for (Annotation[] annos: attr.parameter_annotations)
511 annotationWriter.write(annos, out);
512 return null;
513 }
515 public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {
516 out.writeShort(attr.signature_index);
517 return null;
518 }
520 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) {
521 out.write(attr.debug_extension, 0, attr.debug_extension.length);
522 return null;
523 }
525 public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) {
526 out.writeShort(attr.sourcefile_index);
527 return null;
528 }
530 public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) {
531 out.writeShort(attr.sourceID_index);
532 return null;
533 }
535 public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) {
536 if (stackMapWriter == null)
537 stackMapWriter = new StackMapTableWriter();
539 out.writeShort(attr.entries.length);
540 for (stack_map_frame f: attr.entries)
541 stackMapWriter.write(f, out);
542 return null;
543 }
545 public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) {
546 if (stackMapWriter == null)
547 stackMapWriter = new StackMapTableWriter();
549 out.writeShort(attr.entries.length);
550 for (stack_map_frame f: attr.entries)
551 stackMapWriter.write(f, out);
552 return null;
553 }
555 public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) {
556 return null;
557 }
559 protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) {
560 sharedOut.writeShort(flags.flags);
561 }
563 protected StackMapTableWriter stackMapWriter;
564 }
566 /**
567 * Writer for the frames of StackMap and StackMapTable attributes.
568 */
569 protected static class StackMapTableWriter
570 implements stack_map_frame.Visitor<Void,ClassOutputStream> {
572 public void write(stack_map_frame frame, ClassOutputStream out) {
573 out.write(frame.frame_type);
574 frame.accept(this, out);
575 }
577 public Void visit_same_frame(same_frame frame, ClassOutputStream p) {
578 return null;
579 }
581 public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) {
582 writeVerificationTypeInfo(frame.stack[0], out);
583 return null;
584 }
586 public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) {
587 out.writeShort(frame.offset_delta);
588 writeVerificationTypeInfo(frame.stack[0], out);
589 return null;
590 }
592 public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) {
593 out.writeShort(frame.offset_delta);
594 return null;
595 }
597 public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) {
598 out.writeShort(frame.offset_delta);
599 return null;
600 }
602 public Void visit_append_frame(append_frame frame, ClassOutputStream out) {
603 out.writeShort(frame.offset_delta);
604 for (verification_type_info l: frame.locals)
605 writeVerificationTypeInfo(l, out);
606 return null;
607 }
609 public Void visit_full_frame(full_frame frame, ClassOutputStream out) {
610 out.writeShort(frame.offset_delta);
611 out.writeShort(frame.locals.length);
612 for (verification_type_info l: frame.locals)
613 writeVerificationTypeInfo(l, out);
614 out.writeShort(frame.stack.length);
615 for (verification_type_info s: frame.stack)
616 writeVerificationTypeInfo(s, out);
617 return null;
618 }
620 protected void writeVerificationTypeInfo(verification_type_info info,
621 ClassOutputStream out) {
622 out.write(info.tag);
623 switch (info.tag) {
624 case ITEM_Top:
625 case ITEM_Integer:
626 case ITEM_Float:
627 case ITEM_Long:
628 case ITEM_Double:
629 case ITEM_Null:
630 case ITEM_UninitializedThis:
631 break;
633 case ITEM_Object:
634 Object_variable_info o = (Object_variable_info) info;
635 out.writeShort(o.cpool_index);
636 break;
638 case ITEM_Uninitialized:
639 Uninitialized_variable_info u = (Uninitialized_variable_info) info;
640 out.writeShort(u.offset);
641 break;
643 default:
644 throw new Error();
645 }
646 }
647 }
649 /**
650 * Writer for annotations and the values they contain.
651 */
652 protected static class AnnotationWriter
653 implements Annotation.element_value.Visitor<Void,ClassOutputStream> {
654 public void write(Annotation[] annos, ClassOutputStream out) {
655 out.writeShort(annos.length);
656 for (Annotation anno: annos)
657 write(anno, out);
658 }
660 public void write(Annotation anno, ClassOutputStream out) {
661 out.writeShort(anno.type_index);
662 out.writeShort(anno.element_value_pairs.length);
663 for (element_value_pair p: anno.element_value_pairs)
664 write(p, out);
665 }
667 public void write(element_value_pair pair, ClassOutputStream out) {
668 out.writeShort(pair.element_name_index);
669 write(pair.value, out);
670 }
672 public void write(element_value ev, ClassOutputStream out) {
673 out.writeByte(ev.tag);
674 ev.accept(this, out);
675 }
677 public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) {
678 out.writeShort(ev.const_value_index);
679 return null;
680 }
682 public Void visitEnum(Enum_element_value ev, ClassOutputStream out) {
683 out.writeShort(ev.type_name_index);
684 out.writeShort(ev.const_name_index);
685 return null;
686 }
688 public Void visitClass(Class_element_value ev, ClassOutputStream out) {
689 out.writeShort(ev.class_info_index);
690 return null;
691 }
693 public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) {
694 write(ev.annotation_value, out);
695 return null;
696 }
698 public Void visitArray(Array_element_value ev, ClassOutputStream out) {
699 out.writeShort(ev.num_values);
700 for (element_value v: ev.values)
701 write(v, out);
702 return null;
703 }
705 }
706 }