jjg@308: jjg@46: /* jjg@1521: * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. jjg@46: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jjg@46: * jjg@46: * This code is free software; you can redistribute it and/or modify it jjg@46: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this jjg@46: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. jjg@46: * jjg@46: * This code is distributed in the hope that it will be useful, but WITHOUT jjg@46: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jjg@46: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jjg@46: * version 2 for more details (a copy is included in the LICENSE file that jjg@46: * accompanied this code). jjg@46: * jjg@46: * You should have received a copy of the GNU General Public License version jjg@46: * 2 along with this work; if not, write to the Free Software Foundation, jjg@46: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jjg@46: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. jjg@46: */ jjg@46: jjg@46: package com.sun.tools.classfile; jjg@46: jjg@46: import java.io.ByteArrayOutputStream; jjg@46: import java.io.DataOutputStream; jjg@46: import java.io.File; jjg@46: import java.io.FileOutputStream; jjg@46: import java.io.IOException; jjg@46: import java.io.OutputStream; jjg@46: jjg@46: import static com.sun.tools.classfile.Annotation.*; jjg@46: import static com.sun.tools.classfile.ConstantPool.*; jjg@46: import static com.sun.tools.classfile.StackMapTable_attribute.*; jjg@46: import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*; jjg@46: jjg@46: /** jjg@46: * Write a ClassFile data structure to a file or stream. jjg@46: * jjg@581: *

This is NOT part of any supported API. jjg@581: * If you write code that depends on this, you do so at your own risk. jjg@46: * This code and its internal interfaces are subject to change or jjg@46: * deletion without notice. jjg@46: */ jjg@46: public class ClassWriter { jjg@46: public ClassWriter() { jjg@46: attributeWriter = new AttributeWriter(); jjg@46: constantPoolWriter = new ConstantPoolWriter(); jjg@46: out = new ClassOutputStream(); jjg@46: } jjg@46: jjg@46: /** jjg@46: * Write a ClassFile data structure to a file. jjg@46: */ jjg@46: public void write(ClassFile classFile, File f) throws IOException { jjg@46: FileOutputStream f_out = new FileOutputStream(f); jjg@46: try { jjg@46: write(classFile, f_out); jjg@46: } finally { jjg@46: f_out.close(); jjg@46: } jjg@46: } jjg@46: jjg@46: /** jjg@46: * Write a ClassFile data structure to a stream. jjg@46: */ jjg@46: public void write(ClassFile classFile, OutputStream s) throws IOException { jjg@46: this.classFile = classFile; jjg@46: out.reset(); jjg@46: write(); jjg@46: out.writeTo(s); jjg@46: } jjg@46: jjg@46: protected void write() throws IOException { jjg@46: writeHeader(); jjg@46: writeConstantPool(); jjg@46: writeAccessFlags(classFile.access_flags); jjg@46: writeClassInfo(); jjg@46: writeFields(); jjg@46: writeMethods(); jjg@46: writeAttributes(classFile.attributes); jjg@46: } jjg@46: jjg@46: protected void writeHeader() { jjg@46: out.writeInt(classFile.magic); jjg@46: out.writeShort(classFile.minor_version); jjg@46: out.writeShort(classFile.major_version); jjg@46: } jjg@46: jjg@46: protected void writeAccessFlags(AccessFlags flags) { jjg@46: out.writeShort(flags.flags); jjg@46: } jjg@46: jjg@46: protected void writeAttributes(Attributes attributes) { jjg@46: int size = attributes.size(); jjg@46: out.writeShort(size); jjg@46: for (Attribute attr: attributes) jjg@46: attributeWriter.write(attr, out); jjg@46: } jjg@46: jjg@46: protected void writeClassInfo() { jjg@46: out.writeShort(classFile.this_class); jjg@46: out.writeShort(classFile.super_class); jjg@46: int[] interfaces = classFile.interfaces; jjg@46: out.writeShort(interfaces.length); jjg@46: for (int i: interfaces) jjg@46: out.writeShort(i); jjg@46: } jjg@46: jjg@46: protected void writeDescriptor(Descriptor d) { jjg@46: out.writeShort(d.index); jjg@46: } jjg@46: jjg@46: protected void writeConstantPool() { jjg@46: ConstantPool pool = classFile.constant_pool; jjg@46: int size = pool.size(); jjg@46: out.writeShort(size); jjg@282: for (CPInfo cpInfo: pool.entries()) jjg@282: constantPoolWriter.write(cpInfo, out); jjg@46: } jjg@46: jjg@46: protected void writeFields() throws IOException { jjg@46: Field[] fields = classFile.fields; jjg@46: out.writeShort(fields.length); jjg@46: for (Field f: fields) jjg@46: writeField(f); jjg@46: } jjg@46: jjg@46: protected void writeField(Field f) throws IOException { jjg@46: writeAccessFlags(f.access_flags); jjg@46: out.writeShort(f.name_index); jjg@46: writeDescriptor(f.descriptor); jjg@46: writeAttributes(f.attributes); jjg@46: } jjg@46: jjg@46: protected void writeMethods() throws IOException { jjg@46: Method[] methods = classFile.methods; jjg@46: out.writeShort(methods.length); jjg@46: for (Method m: methods) { jjg@46: writeMethod(m); jjg@46: } jjg@46: } jjg@46: jjg@46: protected void writeMethod(Method m) throws IOException { jjg@46: writeAccessFlags(m.access_flags); jjg@46: out.writeShort(m.name_index); jjg@46: writeDescriptor(m.descriptor); jjg@46: writeAttributes(m.attributes); jjg@46: } jjg@46: jjg@46: protected ClassFile classFile; jjg@46: protected ClassOutputStream out; jjg@46: protected AttributeWriter attributeWriter; jjg@46: protected ConstantPoolWriter constantPoolWriter; jjg@46: jjg@46: /** jjg@46: * Subtype of ByteArrayOutputStream with the convenience methods of jjg@46: * a DataOutputStream. Since ByteArrayOutputStream does not throw jjg@46: * IOException, there are no exceptions from the additional jjg@46: * convenience methods either, jjg@46: */ jjg@46: protected static class ClassOutputStream extends ByteArrayOutputStream { jjg@46: public ClassOutputStream() { jjg@46: d = new DataOutputStream(this); jjg@46: } jjg@46: jjg@46: public void writeByte(int value) { jjg@46: try { jjg@46: d.writeByte(value); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: public void writeShort(int value) { jjg@46: try { jjg@46: d.writeShort(value); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: public void writeInt(int value) { jjg@46: try { jjg@46: d.writeInt(value); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: public void writeLong(long value) { jjg@46: try { jjg@46: d.writeLong(value); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: public void writeFloat(float value) { jjg@46: try { jjg@46: d.writeFloat(value); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: public void writeDouble(double value) { jjg@46: try { jjg@46: d.writeDouble(value); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: public void writeUTF(String value) { jjg@46: try { jjg@46: d.writeUTF(value); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: public void writeTo(ClassOutputStream s) { jjg@46: try { jjg@46: super.writeTo(s); jjg@46: } catch (IOException ignore) { jjg@46: } jjg@46: } jjg@46: jjg@46: private DataOutputStream d; jjg@46: } jjg@46: jjg@46: /** jjg@46: * Writer for the entries in the constant pool. jjg@46: */ jjg@46: protected static class ConstantPoolWriter jjg@46: implements ConstantPool.Visitor { jjg@46: protected int write(CPInfo info, ClassOutputStream out) { jjg@46: out.writeByte(info.getTag()); jjg@46: return info.accept(this, out); jjg@46: } jjg@46: jjg@46: public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) { jjg@46: out.writeShort(info.name_index); jjg@46: return 1; jjg@46: } jjg@46: jjg@46: public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) { jjg@46: out.writeDouble(info.value); jjg@46: return 2; jjg@46: } jjg@46: jjg@46: public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) { jjg@46: writeRef(info, out); jjg@46: return 1; jjg@46: } jjg@46: jjg@46: public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) { jjg@46: out.writeFloat(info.value); jjg@46: return 1; jjg@46: } jjg@46: jjg@46: public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) { jjg@46: out.writeInt(info.value); jjg@46: return 1; jjg@46: } jjg@46: jjg@46: public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) { jjg@46: writeRef(info, out); jjg@46: return 1; jjg@46: } jjg@46: ksrini@826: public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out) { ksrini@826: out.writeShort(info.bootstrap_method_attr_index); ksrini@826: out.writeShort(info.name_and_type_index); ksrini@826: return 1; ksrini@826: } ksrini@826: jjg@46: public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) { jjg@46: out.writeLong(info.value); jjg@46: return 2; jjg@46: } jjg@46: jjg@46: public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) { jjg@46: out.writeShort(info.name_index); jjg@46: out.writeShort(info.type_index); jjg@46: return 1; jjg@46: } jjg@46: ksrini@826: public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) { ksrini@826: out.writeByte(info.reference_kind.tag); ksrini@826: out.writeShort(info.reference_index); ksrini@826: return 1; ksrini@826: } ksrini@826: ksrini@826: public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) { ksrini@826: out.writeShort(info.descriptor_index); ksrini@826: return 1; ksrini@826: } ksrini@826: jjg@46: public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) { jjg@46: return writeRef(info, out); jjg@46: } jjg@46: jjg@46: public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) { jjg@46: out.writeShort(info.string_index); jjg@46: return 1; jjg@46: } jjg@46: jjg@46: public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) { jjg@46: out.writeUTF(info.value); jjg@46: return 1; jjg@46: } jjg@46: jjg@46: protected Integer writeRef(CPRefInfo info, ClassOutputStream out) { jjg@46: out.writeShort(info.class_index); jjg@46: out.writeShort(info.name_and_type_index); jjg@46: return 1; jjg@46: } jjg@46: } jjg@46: jjg@46: /** jjg@46: * Writer for the different types of attribute. jjg@46: */ jjg@46: protected static class AttributeWriter implements Attribute.Visitor { jjg@46: public void write(Attributes attributes, ClassOutputStream out) { jjg@46: int size = attributes.size(); jjg@46: out.writeShort(size); jjg@46: for (Attribute a: attributes) jjg@46: write(a, out); jjg@46: } jjg@46: jjg@46: // Note: due to the use of shared resources, this method is not reentrant. jjg@46: public void write(Attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.attribute_name_index); jjg@46: sharedOut.reset(); jjg@46: attr.accept(this, sharedOut); jjg@46: out.writeInt(sharedOut.size()); jjg@46: sharedOut.writeTo(out); jjg@46: } jjg@46: jjg@46: protected ClassOutputStream sharedOut = new ClassOutputStream(); jjg@46: protected AnnotationWriter annotationWriter = new AnnotationWriter(); jjg@46: jjg@46: public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) { jjg@46: out.write(attr.info, 0, attr.info.length); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) { jjg@46: annotationWriter.write(attr.default_value, out); jjg@46: return null; jjg@46: } jjg@46: ksrini@826: public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) { ksrini@826: out.writeShort(attr.bootstrap_method_specifiers.length); ksrini@826: for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) { ksrini@826: out.writeShort(bsm.bootstrap_method_ref); ksrini@826: int bsm_args_count = bsm.bootstrap_arguments.length; ksrini@826: out.writeShort(bsm_args_count); ksrini@826: for (int i : bsm.bootstrap_arguments) { ksrini@826: out.writeShort(i); ksrini@826: } ksrini@826: } ksrini@826: return null; ksrini@826: } ksrini@826: jjg@46: public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.character_range_table.length); jjg@46: for (CharacterRangeTable_attribute.Entry e: attr.character_range_table) jjg@46: writeCharacterRangeTableEntry(e, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) { jjg@46: out.writeShort(entry.start_pc); jjg@46: out.writeShort(entry.end_pc); jjg@46: out.writeInt(entry.character_range_start); jjg@46: out.writeInt(entry.character_range_end); jjg@46: out.writeShort(entry.flags); jjg@46: } jjg@46: jjg@46: public Void visitCode(Code_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.max_stack); jjg@46: out.writeShort(attr.max_locals); jjg@46: out.writeInt(attr.code.length); jjg@46: out.write(attr.code, 0, attr.code.length); jjg@46: out.writeShort(attr.exception_table.length); jjg@46: for (Code_attribute.Exception_data e: attr.exception_table) jjg@46: writeExceptionTableEntry(e, out); jjg@46: new AttributeWriter().write(attr.attributes, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) { jjg@46: out.writeShort(exception_data.start_pc); jjg@46: out.writeShort(exception_data.end_pc); jjg@46: out.writeShort(exception_data.handler_pc); jjg@46: out.writeShort(exception_data.catch_type); jjg@46: } jjg@46: jjg@46: public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.compilationID_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.constantvalue_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) { jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.class_index); jjg@46: out.writeShort(attr.method_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.exception_index_table.length); jjg@46: for (int i: attr.exception_index_table) jjg@46: out.writeShort(i); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.classes.length); jjg@46: for (InnerClasses_attribute.Info info: attr.classes) jjg@46: writeInnerClassesInfo(info, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) { jjg@46: out.writeShort(info.inner_class_info_index); jjg@46: out.writeShort(info.outer_class_info_index); jjg@46: out.writeShort(info.inner_name_index); jjg@46: writeAccessFlags(info.inner_class_access_flags, out); jjg@46: } jjg@46: jjg@46: public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.line_number_table.length); jjg@46: for (LineNumberTable_attribute.Entry e: attr.line_number_table) jjg@46: writeLineNumberTableEntry(e, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) { jjg@46: out.writeShort(entry.start_pc); jjg@46: out.writeShort(entry.line_number); jjg@46: } jjg@46: jjg@46: public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.local_variable_table.length); jjg@46: for (LocalVariableTable_attribute.Entry e: attr.local_variable_table) jjg@46: writeLocalVariableTableEntry(e, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) { jjg@46: out.writeShort(entry.start_pc); jjg@46: out.writeShort(entry.length); jjg@46: out.writeShort(entry.name_index); jjg@46: out.writeShort(entry.descriptor_index); jjg@46: out.writeShort(entry.index); jjg@46: } jjg@46: jjg@46: public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) { jjg@352: out.writeShort(attr.local_variable_table.length); jjg@46: for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table) jjg@46: writeLocalVariableTypeTableEntry(e, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) { jjg@46: out.writeShort(entry.start_pc); jjg@46: out.writeShort(entry.length); jjg@46: out.writeShort(entry.name_index); jjg@46: out.writeShort(entry.signature_index); jjg@46: out.writeShort(entry.index); jjg@46: } jjg@46: jjg@1473: public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) { jjg@1473: out.writeByte(attr.method_parameter_table.length); jjg@1473: for (MethodParameters_attribute.Entry e : attr.method_parameter_table) { jjg@1473: out.writeShort(e.name_index); ksrini@1592: out.writeShort(e.flags); jjg@1473: } jjg@1473: return null; jjg@1473: } jjg@1473: jjg@46: public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) { jjg@46: annotationWriter.write(attr.annotations, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) { jjg@46: annotationWriter.write(attr.annotations, out); jjg@46: return null; jjg@46: } jjg@46: jjg@1521: public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) { jjg@1521: annotationWriter.write(attr.annotations, out); jjg@1521: return null; jjg@1521: } jjg@1521: jjg@1521: public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) { jjg@1521: annotationWriter.write(attr.annotations, out); jjg@1521: return null; jjg@1521: } jjg@1521: jjg@46: public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) { jjg@46: out.writeByte(attr.parameter_annotations.length); jjg@46: for (Annotation[] annos: attr.parameter_annotations) jjg@46: annotationWriter.write(annos, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) { jjg@46: out.writeByte(attr.parameter_annotations.length); jjg@46: for (Annotation[] annos: attr.parameter_annotations) jjg@46: annotationWriter.write(annos, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitSignature(Signature_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.signature_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) { jjg@46: out.write(attr.debug_extension, 0, attr.debug_extension.length); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.sourcefile_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) { jjg@46: out.writeShort(attr.sourceID_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) { jjg@46: if (stackMapWriter == null) jjg@46: stackMapWriter = new StackMapTableWriter(); jjg@46: jjg@46: out.writeShort(attr.entries.length); jjg@46: for (stack_map_frame f: attr.entries) jjg@46: stackMapWriter.write(f, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) { jjg@46: if (stackMapWriter == null) jjg@46: stackMapWriter = new StackMapTableWriter(); jjg@46: jjg@46: out.writeShort(attr.entries.length); jjg@46: for (stack_map_frame f: attr.entries) jjg@46: stackMapWriter.write(f, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) { jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeAccessFlags(AccessFlags flags, ClassOutputStream p) { jjg@46: sharedOut.writeShort(flags.flags); jjg@46: } jjg@46: jjg@46: protected StackMapTableWriter stackMapWriter; jjg@46: } jjg@46: jjg@46: /** jjg@46: * Writer for the frames of StackMap and StackMapTable attributes. jjg@46: */ jjg@46: protected static class StackMapTableWriter jjg@46: implements stack_map_frame.Visitor { jjg@46: jjg@46: public void write(stack_map_frame frame, ClassOutputStream out) { jjg@46: out.write(frame.frame_type); jjg@46: frame.accept(this, out); jjg@46: } jjg@46: jjg@46: public Void visit_same_frame(same_frame frame, ClassOutputStream p) { jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) { jjg@46: writeVerificationTypeInfo(frame.stack[0], out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) { jjg@46: out.writeShort(frame.offset_delta); jjg@46: writeVerificationTypeInfo(frame.stack[0], out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) { jjg@46: out.writeShort(frame.offset_delta); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) { jjg@46: out.writeShort(frame.offset_delta); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visit_append_frame(append_frame frame, ClassOutputStream out) { jjg@46: out.writeShort(frame.offset_delta); jjg@46: for (verification_type_info l: frame.locals) jjg@46: writeVerificationTypeInfo(l, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visit_full_frame(full_frame frame, ClassOutputStream out) { jjg@46: out.writeShort(frame.offset_delta); jjg@46: out.writeShort(frame.locals.length); jjg@46: for (verification_type_info l: frame.locals) jjg@46: writeVerificationTypeInfo(l, out); jjg@46: out.writeShort(frame.stack.length); jjg@46: for (verification_type_info s: frame.stack) jjg@46: writeVerificationTypeInfo(s, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: protected void writeVerificationTypeInfo(verification_type_info info, jjg@46: ClassOutputStream out) { jjg@46: out.write(info.tag); jjg@46: switch (info.tag) { jjg@46: case ITEM_Top: jjg@46: case ITEM_Integer: jjg@46: case ITEM_Float: jjg@46: case ITEM_Long: jjg@46: case ITEM_Double: jjg@46: case ITEM_Null: jjg@46: case ITEM_UninitializedThis: jjg@46: break; jjg@46: jjg@46: case ITEM_Object: jjg@46: Object_variable_info o = (Object_variable_info) info; jjg@46: out.writeShort(o.cpool_index); jjg@46: break; jjg@46: jjg@46: case ITEM_Uninitialized: jjg@46: Uninitialized_variable_info u = (Uninitialized_variable_info) info; jjg@46: out.writeShort(u.offset); jjg@46: break; jjg@46: jjg@46: default: jjg@46: throw new Error(); jjg@46: } jjg@46: } jjg@46: } jjg@46: jjg@46: /** jjg@46: * Writer for annotations and the values they contain. jjg@46: */ jjg@46: protected static class AnnotationWriter jjg@46: implements Annotation.element_value.Visitor { jjg@46: public void write(Annotation[] annos, ClassOutputStream out) { jjg@46: out.writeShort(annos.length); jjg@46: for (Annotation anno: annos) jjg@46: write(anno, out); jjg@46: } jjg@46: jjg@1521: public void write(TypeAnnotation[] annos, ClassOutputStream out) { jjg@1521: out.writeShort(annos.length); jjg@1521: for (TypeAnnotation anno: annos) jjg@1521: write(anno, out); jjg@1521: } jjg@1521: jjg@46: public void write(Annotation anno, ClassOutputStream out) { jjg@46: out.writeShort(anno.type_index); jjg@46: out.writeShort(anno.element_value_pairs.length); jjg@46: for (element_value_pair p: anno.element_value_pairs) jjg@46: write(p, out); jjg@46: } jjg@46: jjg@1521: public void write(TypeAnnotation anno, ClassOutputStream out) { jjg@1521: write(anno.position, out); jjg@1521: write(anno.annotation, out); jjg@1521: } jjg@1521: jjg@46: public void write(element_value_pair pair, ClassOutputStream out) { jjg@46: out.writeShort(pair.element_name_index); jjg@46: write(pair.value, out); jjg@46: } jjg@46: jjg@46: public void write(element_value ev, ClassOutputStream out) { jjg@46: out.writeByte(ev.tag); jjg@46: ev.accept(this, out); jjg@46: } jjg@46: jjg@46: public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) { jjg@46: out.writeShort(ev.const_value_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitEnum(Enum_element_value ev, ClassOutputStream out) { jjg@46: out.writeShort(ev.type_name_index); jjg@46: out.writeShort(ev.const_name_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitClass(Class_element_value ev, ClassOutputStream out) { jjg@46: out.writeShort(ev.class_info_index); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) { jjg@46: write(ev.annotation_value, out); jjg@46: return null; jjg@46: } jjg@46: jjg@46: public Void visitArray(Array_element_value ev, ClassOutputStream out) { jjg@46: out.writeShort(ev.num_values); jjg@46: for (element_value v: ev.values) jjg@46: write(v, out); jjg@46: return null; jjg@46: } jjg@308: jjg@1521: // TODO: Move this to TypeAnnotation to be closer with similar logic? jjg@1521: private void write(TypeAnnotation.Position p, ClassOutputStream out) { jjg@1521: out.writeByte(p.type.targetTypeValue()); jjg@1521: switch (p.type) { jjg@1521: // instanceof jjg@1521: case INSTANCEOF: jjg@1521: // new expression jjg@1521: case NEW: jjg@1563: // constructor/method reference receiver jjg@1563: case CONSTRUCTOR_REFERENCE: jjg@1563: case METHOD_REFERENCE: jjg@1521: out.writeShort(p.offset); jjg@1521: break; jjg@1521: // local variable jjg@1521: case LOCAL_VARIABLE: jjg@1521: // resource variable jjg@1521: case RESOURCE_VARIABLE: jjg@1521: int table_length = p.lvarOffset.length; jjg@1521: out.writeShort(table_length); jjg@1521: for (int i = 0; i < table_length; ++i) { jjg@1521: out.writeShort(1); // for table length jjg@1521: out.writeShort(p.lvarOffset[i]); jjg@1521: out.writeShort(p.lvarLength[i]); jjg@1521: out.writeShort(p.lvarIndex[i]); jjg@1521: } jjg@1521: break; jjg@1521: // exception parameter jjg@1521: case EXCEPTION_PARAMETER: jjg@1521: out.writeByte(p.exception_index); jjg@1521: break; jjg@1521: // method receiver jjg@1521: case METHOD_RECEIVER: jjg@1521: // Do nothing jjg@1521: break; jjg@1521: // type parameters jjg@1521: case CLASS_TYPE_PARAMETER: jjg@1521: case METHOD_TYPE_PARAMETER: jjg@1521: out.writeByte(p.parameter_index); jjg@1521: break; jjg@1521: // type parameters bounds jjg@1521: case CLASS_TYPE_PARAMETER_BOUND: jjg@1521: case METHOD_TYPE_PARAMETER_BOUND: jjg@1521: out.writeByte(p.parameter_index); jjg@1521: out.writeByte(p.bound_index); jjg@1521: break; jjg@1521: // class extends or implements clause jjg@1521: case CLASS_EXTENDS: jjg@1521: out.writeByte(p.type_index); jjg@1521: break; jjg@1521: // throws jjg@1521: case THROWS: jjg@1521: out.writeByte(p.type_index); jjg@1521: break; jjg@1521: // method parameter jjg@1521: case METHOD_FORMAL_PARAMETER: jjg@1521: out.writeByte(p.parameter_index); jjg@1521: break; jjg@1563: // type cast jjg@1563: case CAST: jjg@1521: // method/constructor/reference type argument jjg@1521: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: jjg@1521: case METHOD_INVOCATION_TYPE_ARGUMENT: jjg@1563: case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: jjg@1521: case METHOD_REFERENCE_TYPE_ARGUMENT: jjg@1521: out.writeShort(p.offset); jjg@1521: out.writeByte(p.type_index); jjg@1521: break; jjg@1521: // We don't need to worry about these jjg@1521: case METHOD_RETURN: jjg@1521: case FIELD: jjg@1521: break; jjg@1521: case UNKNOWN: jjg@1521: throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!"); jjg@1521: default: jjg@1521: throw new AssertionError("ClassWriter: Unknown target type for position: " + p); jjg@1521: } jjg@1521: jjg@1521: { // Append location data for generics/arrays. jjg@1521: // TODO: check for overrun? jjg@1521: out.writeByte((byte)p.location.size()); jjg@1521: for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location)) jjg@1521: out.writeByte((byte)i); jjg@1521: } jjg@1521: } jjg@46: } jjg@46: }