All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.langtools.classfile.ClassWriter Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version

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

package com.redhat.ceylon.langtools.classfile;

import static com.redhat.ceylon.langtools.classfile.Annotation.*;
import static com.redhat.ceylon.langtools.classfile.ConstantPool.*;
import static com.redhat.ceylon.langtools.classfile.StackMapTable_attribute.*;
import static com.redhat.ceylon.langtools.classfile.StackMapTable_attribute.verification_type_info.*;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Write a ClassFile data structure to a file or stream.
 *
 *  

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





© 2015 - 2024 Weber Informatics LLC | Privacy Policy