Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java
38899 views
1/*2* Copyright (c) 2008, 2013, Oracle and/or its affiliates. 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 it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation. Oracle designates this8* particular file as subject to the "Classpath" exception as provided9* by Oracle in the LICENSE file that accompanied this code.10*11* This code is distributed in the hope that it will be useful, but WITHOUT12* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or13* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License14* version 2 for more details (a copy is included in the LICENSE file that15* accompanied this code).16*17* You should have received a copy of the GNU General Public License version18* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA22* or visit www.oracle.com if you need additional information or have any23* questions.24*/2526package com.sun.tools.classfile;2728import java.io.ByteArrayOutputStream;29import java.io.DataOutputStream;30import java.io.File;31import java.io.FileOutputStream;32import java.io.IOException;33import java.io.OutputStream;3435import static com.sun.tools.classfile.Annotation.*;36import static com.sun.tools.classfile.ConstantPool.*;37import static com.sun.tools.classfile.StackMapTable_attribute.*;38import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*;3940/**41* Write a ClassFile data structure to a file or stream.42*43* <p><b>This is NOT part of any supported API.44* If 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 or46* deletion without notice.</b>47*/48public class ClassWriter {49public ClassWriter() {50attributeWriter = new AttributeWriter();51constantPoolWriter = new ConstantPoolWriter();52out = new ClassOutputStream();53}5455/**56* Write a ClassFile data structure to a file.57*/58public void write(ClassFile classFile, File f) throws IOException {59FileOutputStream f_out = new FileOutputStream(f);60try {61write(classFile, f_out);62} finally {63f_out.close();64}65}6667/**68* Write a ClassFile data structure to a stream.69*/70public void write(ClassFile classFile, OutputStream s) throws IOException {71this.classFile = classFile;72out.reset();73write();74out.writeTo(s);75}7677protected void write() throws IOException {78writeHeader();79writeConstantPool();80writeAccessFlags(classFile.access_flags);81writeClassInfo();82writeFields();83writeMethods();84writeAttributes(classFile.attributes);85}8687protected void writeHeader() {88out.writeInt(classFile.magic);89out.writeShort(classFile.minor_version);90out.writeShort(classFile.major_version);91}9293protected void writeAccessFlags(AccessFlags flags) {94out.writeShort(flags.flags);95}9697protected void writeAttributes(Attributes attributes) {98int size = attributes.size();99out.writeShort(size);100for (Attribute attr: attributes)101attributeWriter.write(attr, out);102}103104protected void writeClassInfo() {105out.writeShort(classFile.this_class);106out.writeShort(classFile.super_class);107int[] interfaces = classFile.interfaces;108out.writeShort(interfaces.length);109for (int i: interfaces)110out.writeShort(i);111}112113protected void writeDescriptor(Descriptor d) {114out.writeShort(d.index);115}116117protected void writeConstantPool() {118ConstantPool pool = classFile.constant_pool;119int size = pool.size();120out.writeShort(size);121for (CPInfo cpInfo: pool.entries())122constantPoolWriter.write(cpInfo, out);123}124125protected void writeFields() throws IOException {126Field[] fields = classFile.fields;127out.writeShort(fields.length);128for (Field f: fields)129writeField(f);130}131132protected void writeField(Field f) throws IOException {133writeAccessFlags(f.access_flags);134out.writeShort(f.name_index);135writeDescriptor(f.descriptor);136writeAttributes(f.attributes);137}138139protected void writeMethods() throws IOException {140Method[] methods = classFile.methods;141out.writeShort(methods.length);142for (Method m: methods) {143writeMethod(m);144}145}146147protected void writeMethod(Method m) throws IOException {148writeAccessFlags(m.access_flags);149out.writeShort(m.name_index);150writeDescriptor(m.descriptor);151writeAttributes(m.attributes);152}153154protected ClassFile classFile;155protected ClassOutputStream out;156protected AttributeWriter attributeWriter;157protected ConstantPoolWriter constantPoolWriter;158159/**160* Subtype of ByteArrayOutputStream with the convenience methods of161* a DataOutputStream. Since ByteArrayOutputStream does not throw162* IOException, there are no exceptions from the additional163* convenience methods either,164*/165protected static class ClassOutputStream extends ByteArrayOutputStream {166public ClassOutputStream() {167d = new DataOutputStream(this);168}169170public void writeByte(int value) {171try {172d.writeByte(value);173} catch (IOException ignore) {174}175}176177public void writeShort(int value) {178try {179d.writeShort(value);180} catch (IOException ignore) {181}182}183184public void writeInt(int value) {185try {186d.writeInt(value);187} catch (IOException ignore) {188}189}190191public void writeLong(long value) {192try {193d.writeLong(value);194} catch (IOException ignore) {195}196}197198public void writeFloat(float value) {199try {200d.writeFloat(value);201} catch (IOException ignore) {202}203}204205public void writeDouble(double value) {206try {207d.writeDouble(value);208} catch (IOException ignore) {209}210}211212public void writeUTF(String value) {213try {214d.writeUTF(value);215} catch (IOException ignore) {216}217}218219public void writeTo(ClassOutputStream s) {220try {221super.writeTo(s);222} catch (IOException ignore) {223}224}225226private DataOutputStream d;227}228229/**230* Writer for the entries in the constant pool.231*/232protected static class ConstantPoolWriter233implements ConstantPool.Visitor<Integer,ClassOutputStream> {234protected int write(CPInfo info, ClassOutputStream out) {235out.writeByte(info.getTag());236return info.accept(this, out);237}238239public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) {240out.writeShort(info.name_index);241return 1;242}243244public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) {245out.writeDouble(info.value);246return 2;247}248249public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) {250writeRef(info, out);251return 1;252}253254public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) {255out.writeFloat(info.value);256return 1;257}258259public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) {260out.writeInt(info.value);261return 1;262}263264public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) {265writeRef(info, out);266return 1;267}268269public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out) {270out.writeShort(info.bootstrap_method_attr_index);271out.writeShort(info.name_and_type_index);272return 1;273}274275public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) {276out.writeLong(info.value);277return 2;278}279280public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) {281out.writeShort(info.name_index);282out.writeShort(info.type_index);283return 1;284}285286public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) {287out.writeByte(info.reference_kind.tag);288out.writeShort(info.reference_index);289return 1;290}291292public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) {293out.writeShort(info.descriptor_index);294return 1;295}296297public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) {298return writeRef(info, out);299}300301public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) {302out.writeShort(info.string_index);303return 1;304}305306public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) {307out.writeUTF(info.value);308return 1;309}310311protected Integer writeRef(CPRefInfo info, ClassOutputStream out) {312out.writeShort(info.class_index);313out.writeShort(info.name_and_type_index);314return 1;315}316}317318/**319* Writer for the different types of attribute.320*/321protected static class AttributeWriter implements Attribute.Visitor<Void,ClassOutputStream> {322public void write(Attributes attributes, ClassOutputStream out) {323int size = attributes.size();324out.writeShort(size);325for (Attribute a: attributes)326write(a, out);327}328329// Note: due to the use of shared resources, this method is not reentrant.330public void write(Attribute attr, ClassOutputStream out) {331out.writeShort(attr.attribute_name_index);332sharedOut.reset();333attr.accept(this, sharedOut);334out.writeInt(sharedOut.size());335sharedOut.writeTo(out);336}337338protected ClassOutputStream sharedOut = new ClassOutputStream();339protected AnnotationWriter annotationWriter = new AnnotationWriter();340341public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) {342out.write(attr.info, 0, attr.info.length);343return null;344}345346public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) {347annotationWriter.write(attr.default_value, out);348return null;349}350351public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) {352out.writeShort(attr.bootstrap_method_specifiers.length);353for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) {354out.writeShort(bsm.bootstrap_method_ref);355int bsm_args_count = bsm.bootstrap_arguments.length;356out.writeShort(bsm_args_count);357for (int i : bsm.bootstrap_arguments) {358out.writeShort(i);359}360}361return null;362}363364public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) {365out.writeShort(attr.character_range_table.length);366for (CharacterRangeTable_attribute.Entry e: attr.character_range_table)367writeCharacterRangeTableEntry(e, out);368return null;369}370371protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) {372out.writeShort(entry.start_pc);373out.writeShort(entry.end_pc);374out.writeInt(entry.character_range_start);375out.writeInt(entry.character_range_end);376out.writeShort(entry.flags);377}378379public Void visitCode(Code_attribute attr, ClassOutputStream out) {380out.writeShort(attr.max_stack);381out.writeShort(attr.max_locals);382out.writeInt(attr.code.length);383out.write(attr.code, 0, attr.code.length);384out.writeShort(attr.exception_table.length);385for (Code_attribute.Exception_data e: attr.exception_table)386writeExceptionTableEntry(e, out);387new AttributeWriter().write(attr.attributes, out);388return null;389}390391protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) {392out.writeShort(exception_data.start_pc);393out.writeShort(exception_data.end_pc);394out.writeShort(exception_data.handler_pc);395out.writeShort(exception_data.catch_type);396}397398public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) {399out.writeShort(attr.compilationID_index);400return null;401}402403public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) {404out.writeShort(attr.constantvalue_index);405return null;406}407408public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) {409return null;410}411412public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) {413out.writeShort(attr.class_index);414out.writeShort(attr.method_index);415return null;416}417418public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) {419out.writeShort(attr.exception_index_table.length);420for (int i: attr.exception_index_table)421out.writeShort(i);422return null;423}424425public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) {426out.writeShort(attr.classes.length);427for (InnerClasses_attribute.Info info: attr.classes)428writeInnerClassesInfo(info, out);429return null;430}431432protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) {433out.writeShort(info.inner_class_info_index);434out.writeShort(info.outer_class_info_index);435out.writeShort(info.inner_name_index);436writeAccessFlags(info.inner_class_access_flags, out);437}438439public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) {440out.writeShort(attr.line_number_table.length);441for (LineNumberTable_attribute.Entry e: attr.line_number_table)442writeLineNumberTableEntry(e, out);443return null;444}445446protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) {447out.writeShort(entry.start_pc);448out.writeShort(entry.line_number);449}450451public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) {452out.writeShort(attr.local_variable_table.length);453for (LocalVariableTable_attribute.Entry e: attr.local_variable_table)454writeLocalVariableTableEntry(e, out);455return null;456}457458protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) {459out.writeShort(entry.start_pc);460out.writeShort(entry.length);461out.writeShort(entry.name_index);462out.writeShort(entry.descriptor_index);463out.writeShort(entry.index);464}465466public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) {467out.writeShort(attr.local_variable_table.length);468for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table)469writeLocalVariableTypeTableEntry(e, out);470return null;471}472473protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) {474out.writeShort(entry.start_pc);475out.writeShort(entry.length);476out.writeShort(entry.name_index);477out.writeShort(entry.signature_index);478out.writeShort(entry.index);479}480481public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) {482out.writeByte(attr.method_parameter_table.length);483for (MethodParameters_attribute.Entry e : attr.method_parameter_table) {484out.writeShort(e.name_index);485out.writeShort(e.flags);486}487return null;488}489490public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {491annotationWriter.write(attr.annotations, out);492return null;493}494495public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) {496annotationWriter.write(attr.annotations, out);497return null;498}499500public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) {501annotationWriter.write(attr.annotations, out);502return null;503}504505public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) {506annotationWriter.write(attr.annotations, out);507return null;508}509510public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) {511out.writeByte(attr.parameter_annotations.length);512for (Annotation[] annos: attr.parameter_annotations)513annotationWriter.write(annos, out);514return null;515}516517public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) {518out.writeByte(attr.parameter_annotations.length);519for (Annotation[] annos: attr.parameter_annotations)520annotationWriter.write(annos, out);521return null;522}523524public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {525out.writeShort(attr.signature_index);526return null;527}528529public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) {530out.write(attr.debug_extension, 0, attr.debug_extension.length);531return null;532}533534public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) {535out.writeShort(attr.sourcefile_index);536return null;537}538539public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) {540out.writeShort(attr.sourceID_index);541return null;542}543544public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) {545if (stackMapWriter == null)546stackMapWriter = new StackMapTableWriter();547548out.writeShort(attr.entries.length);549for (stack_map_frame f: attr.entries)550stackMapWriter.write(f, out);551return null;552}553554public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) {555if (stackMapWriter == null)556stackMapWriter = new StackMapTableWriter();557558out.writeShort(attr.entries.length);559for (stack_map_frame f: attr.entries)560stackMapWriter.write(f, out);561return null;562}563564public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) {565return null;566}567568protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) {569sharedOut.writeShort(flags.flags);570}571572protected StackMapTableWriter stackMapWriter;573}574575/**576* Writer for the frames of StackMap and StackMapTable attributes.577*/578protected static class StackMapTableWriter579implements stack_map_frame.Visitor<Void,ClassOutputStream> {580581public void write(stack_map_frame frame, ClassOutputStream out) {582out.write(frame.frame_type);583frame.accept(this, out);584}585586public Void visit_same_frame(same_frame frame, ClassOutputStream p) {587return null;588}589590public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) {591writeVerificationTypeInfo(frame.stack[0], out);592return null;593}594595public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) {596out.writeShort(frame.offset_delta);597writeVerificationTypeInfo(frame.stack[0], out);598return null;599}600601public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) {602out.writeShort(frame.offset_delta);603return null;604}605606public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) {607out.writeShort(frame.offset_delta);608return null;609}610611public Void visit_append_frame(append_frame frame, ClassOutputStream out) {612out.writeShort(frame.offset_delta);613for (verification_type_info l: frame.locals)614writeVerificationTypeInfo(l, out);615return null;616}617618public Void visit_full_frame(full_frame frame, ClassOutputStream out) {619out.writeShort(frame.offset_delta);620out.writeShort(frame.locals.length);621for (verification_type_info l: frame.locals)622writeVerificationTypeInfo(l, out);623out.writeShort(frame.stack.length);624for (verification_type_info s: frame.stack)625writeVerificationTypeInfo(s, out);626return null;627}628629protected void writeVerificationTypeInfo(verification_type_info info,630ClassOutputStream out) {631out.write(info.tag);632switch (info.tag) {633case ITEM_Top:634case ITEM_Integer:635case ITEM_Float:636case ITEM_Long:637case ITEM_Double:638case ITEM_Null:639case ITEM_UninitializedThis:640break;641642case ITEM_Object:643Object_variable_info o = (Object_variable_info) info;644out.writeShort(o.cpool_index);645break;646647case ITEM_Uninitialized:648Uninitialized_variable_info u = (Uninitialized_variable_info) info;649out.writeShort(u.offset);650break;651652default:653throw new Error();654}655}656}657658/**659* Writer for annotations and the values they contain.660*/661protected static class AnnotationWriter662implements Annotation.element_value.Visitor<Void,ClassOutputStream> {663public void write(Annotation[] annos, ClassOutputStream out) {664out.writeShort(annos.length);665for (Annotation anno: annos)666write(anno, out);667}668669public void write(TypeAnnotation[] annos, ClassOutputStream out) {670out.writeShort(annos.length);671for (TypeAnnotation anno: annos)672write(anno, out);673}674675public void write(Annotation anno, ClassOutputStream out) {676out.writeShort(anno.type_index);677out.writeShort(anno.element_value_pairs.length);678for (element_value_pair p: anno.element_value_pairs)679write(p, out);680}681682public void write(TypeAnnotation anno, ClassOutputStream out) {683write(anno.position, out);684write(anno.annotation, out);685}686687public void write(element_value_pair pair, ClassOutputStream out) {688out.writeShort(pair.element_name_index);689write(pair.value, out);690}691692public void write(element_value ev, ClassOutputStream out) {693out.writeByte(ev.tag);694ev.accept(this, out);695}696697public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) {698out.writeShort(ev.const_value_index);699return null;700}701702public Void visitEnum(Enum_element_value ev, ClassOutputStream out) {703out.writeShort(ev.type_name_index);704out.writeShort(ev.const_name_index);705return null;706}707708public Void visitClass(Class_element_value ev, ClassOutputStream out) {709out.writeShort(ev.class_info_index);710return null;711}712713public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) {714write(ev.annotation_value, out);715return null;716}717718public Void visitArray(Array_element_value ev, ClassOutputStream out) {719out.writeShort(ev.num_values);720for (element_value v: ev.values)721write(v, out);722return null;723}724725// TODO: Move this to TypeAnnotation to be closer with similar logic?726private void write(TypeAnnotation.Position p, ClassOutputStream out) {727out.writeByte(p.type.targetTypeValue());728switch (p.type) {729// instanceof730case INSTANCEOF:731// new expression732case NEW:733// constructor/method reference receiver734case CONSTRUCTOR_REFERENCE:735case METHOD_REFERENCE:736out.writeShort(p.offset);737break;738// local variable739case LOCAL_VARIABLE:740// resource variable741case RESOURCE_VARIABLE:742int table_length = p.lvarOffset.length;743out.writeShort(table_length);744for (int i = 0; i < table_length; ++i) {745out.writeShort(1); // for table length746out.writeShort(p.lvarOffset[i]);747out.writeShort(p.lvarLength[i]);748out.writeShort(p.lvarIndex[i]);749}750break;751// exception parameter752case EXCEPTION_PARAMETER:753out.writeShort(p.exception_index);754break;755// method receiver756case METHOD_RECEIVER:757// Do nothing758break;759// type parameters760case CLASS_TYPE_PARAMETER:761case METHOD_TYPE_PARAMETER:762out.writeByte(p.parameter_index);763break;764// type parameters bounds765case CLASS_TYPE_PARAMETER_BOUND:766case METHOD_TYPE_PARAMETER_BOUND:767out.writeByte(p.parameter_index);768out.writeByte(p.bound_index);769break;770// class extends or implements clause771case CLASS_EXTENDS:772out.writeShort(p.type_index);773break;774// throws775case THROWS:776out.writeShort(p.type_index);777break;778// method parameter779case METHOD_FORMAL_PARAMETER:780out.writeByte(p.parameter_index);781break;782// type cast783case CAST:784// method/constructor/reference type argument785case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:786case METHOD_INVOCATION_TYPE_ARGUMENT:787case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:788case METHOD_REFERENCE_TYPE_ARGUMENT:789out.writeShort(p.offset);790out.writeByte(p.type_index);791break;792// We don't need to worry about these793case METHOD_RETURN:794case FIELD:795break;796case UNKNOWN:797throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!");798default:799throw new AssertionError("ClassWriter: Unknown target type for position: " + p);800}801802{ // Append location data for generics/arrays.803// TODO: check for overrun?804out.writeByte((byte)p.location.size());805for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location))806out.writeByte((byte)i);807}808}809}810}811812813