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

Tue, 19 May 2009 11:50:54 -0700

author
jjg
date
Tue, 19 May 2009 11:50:54 -0700
changeset 283
cd0630109de5
parent 282
fc634a593812
child 308
03944ee4fac4
permissions
-rw-r--r--

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 }

mercurial