Mon, 28 Feb 2011 11:48:53 +0000
7015430: Incorrect thrown type determined for unchecked invocations
Summary: Thrown types do not get updated after 15.12.2.8, and do not get erased as per 15.12.2.6
Reviewed-by: jjg, dlsmith
2 /*
3 * Copyright (c) 2008, 2011, 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 visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {
483 annotationWriter.write(attr.annotations, out);
484 return null;
485 }
487 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) {
488 annotationWriter.write(attr.annotations, out);
489 return null;
490 }
492 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_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 }
499 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
500 out.writeByte(attr.parameter_annotations.length);
501 for (Annotation[] annos: attr.parameter_annotations)
502 annotationWriter.write(annos, out);
503 return null;
504 }
506 public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {
507 out.writeShort(attr.signature_index);
508 return null;
509 }
511 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) {
512 out.write(attr.debug_extension, 0, attr.debug_extension.length);
513 return null;
514 }
516 public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) {
517 out.writeShort(attr.sourcefile_index);
518 return null;
519 }
521 public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) {
522 out.writeShort(attr.sourceID_index);
523 return null;
524 }
526 public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) {
527 if (stackMapWriter == null)
528 stackMapWriter = new StackMapTableWriter();
530 out.writeShort(attr.entries.length);
531 for (stack_map_frame f: attr.entries)
532 stackMapWriter.write(f, out);
533 return null;
534 }
536 public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) {
537 if (stackMapWriter == null)
538 stackMapWriter = new StackMapTableWriter();
540 out.writeShort(attr.entries.length);
541 for (stack_map_frame f: attr.entries)
542 stackMapWriter.write(f, out);
543 return null;
544 }
546 public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) {
547 return null;
548 }
550 protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) {
551 sharedOut.writeShort(flags.flags);
552 }
554 protected StackMapTableWriter stackMapWriter;
555 }
557 /**
558 * Writer for the frames of StackMap and StackMapTable attributes.
559 */
560 protected static class StackMapTableWriter
561 implements stack_map_frame.Visitor<Void,ClassOutputStream> {
563 public void write(stack_map_frame frame, ClassOutputStream out) {
564 out.write(frame.frame_type);
565 frame.accept(this, out);
566 }
568 public Void visit_same_frame(same_frame frame, ClassOutputStream p) {
569 return null;
570 }
572 public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) {
573 writeVerificationTypeInfo(frame.stack[0], out);
574 return null;
575 }
577 public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) {
578 out.writeShort(frame.offset_delta);
579 writeVerificationTypeInfo(frame.stack[0], out);
580 return null;
581 }
583 public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) {
584 out.writeShort(frame.offset_delta);
585 return null;
586 }
588 public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) {
589 out.writeShort(frame.offset_delta);
590 return null;
591 }
593 public Void visit_append_frame(append_frame frame, ClassOutputStream out) {
594 out.writeShort(frame.offset_delta);
595 for (verification_type_info l: frame.locals)
596 writeVerificationTypeInfo(l, out);
597 return null;
598 }
600 public Void visit_full_frame(full_frame frame, ClassOutputStream out) {
601 out.writeShort(frame.offset_delta);
602 out.writeShort(frame.locals.length);
603 for (verification_type_info l: frame.locals)
604 writeVerificationTypeInfo(l, out);
605 out.writeShort(frame.stack.length);
606 for (verification_type_info s: frame.stack)
607 writeVerificationTypeInfo(s, out);
608 return null;
609 }
611 protected void writeVerificationTypeInfo(verification_type_info info,
612 ClassOutputStream out) {
613 out.write(info.tag);
614 switch (info.tag) {
615 case ITEM_Top:
616 case ITEM_Integer:
617 case ITEM_Float:
618 case ITEM_Long:
619 case ITEM_Double:
620 case ITEM_Null:
621 case ITEM_UninitializedThis:
622 break;
624 case ITEM_Object:
625 Object_variable_info o = (Object_variable_info) info;
626 out.writeShort(o.cpool_index);
627 break;
629 case ITEM_Uninitialized:
630 Uninitialized_variable_info u = (Uninitialized_variable_info) info;
631 out.writeShort(u.offset);
632 break;
634 default:
635 throw new Error();
636 }
637 }
638 }
640 /**
641 * Writer for annotations and the values they contain.
642 */
643 protected static class AnnotationWriter
644 implements Annotation.element_value.Visitor<Void,ClassOutputStream> {
645 public void write(Annotation[] annos, ClassOutputStream out) {
646 out.writeShort(annos.length);
647 for (Annotation anno: annos)
648 write(anno, out);
649 }
651 public void write(Annotation anno, ClassOutputStream out) {
652 out.writeShort(anno.type_index);
653 out.writeShort(anno.element_value_pairs.length);
654 for (element_value_pair p: anno.element_value_pairs)
655 write(p, out);
656 }
658 public void write(element_value_pair pair, ClassOutputStream out) {
659 out.writeShort(pair.element_name_index);
660 write(pair.value, out);
661 }
663 public void write(element_value ev, ClassOutputStream out) {
664 out.writeByte(ev.tag);
665 ev.accept(this, out);
666 }
668 public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) {
669 out.writeShort(ev.const_value_index);
670 return null;
671 }
673 public Void visitEnum(Enum_element_value ev, ClassOutputStream out) {
674 out.writeShort(ev.type_name_index);
675 out.writeShort(ev.const_name_index);
676 return null;
677 }
679 public Void visitClass(Class_element_value ev, ClassOutputStream out) {
680 out.writeShort(ev.class_info_index);
681 return null;
682 }
684 public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) {
685 write(ev.annotation_value, out);
686 return null;
687 }
689 public Void visitArray(Array_element_value ev, ClassOutputStream out) {
690 out.writeShort(ev.num_values);
691 for (element_value v: ev.values)
692 write(v, out);
693 return null;
694 }
696 }
697 }