001package serp.bytecode;
002
003import java.io.*;
004import java.lang.reflect.*;
005import java.util.*;
006
007import serp.bytecode.lowlevel.*;
008import serp.bytecode.visitor.*;
009import serp.util.*;
010
011/**
012 * In bytecode attributes are used to represent anything that is not
013 * part of the class structure. This includes the source file name, code of
014 * methods, the line number table, etc. All attributes contain at a minimum
015 * an immutable name that also determines the attribute's type.
016 *
017 * @author Abe White
018 */
019public abstract class Attribute extends Attributes implements VisitAcceptor {
020    private int _nameIndex = 0;
021    private Attributes _owner = null;
022
023    Attribute(int nameIndex, Attributes owner) {
024        _owner = owner;
025        _nameIndex = nameIndex;
026    }
027
028    /**
029     * Create an attribute of the appropriate type based on the
030     * the attribute name.
031     */
032    static Attribute create(String name, Attributes owner) {
033        // special case for annotations
034        int nameIndex = owner.getPool().findUTF8Entry(name, true);
035        if ("RuntimeVisibleAnnotations".equals(name)
036            || "RuntimeInvisibleAnnotations".equals(name))
037            return new Annotations(nameIndex, owner);
038
039        try {
040            Class type = Class.forName("serp.bytecode." + name);
041            Constructor cons = type.getDeclaredConstructor(new Class[] {
042                int.class, Attributes.class
043            });
044            return (Attribute) cons.newInstance(new Object[] {
045                Numbers.valueOf(nameIndex), owner
046            });
047        } catch (Throwable t) {
048            return new UnknownAttribute(nameIndex, owner);
049        }
050    }
051
052    /**
053     * Return the {@link Attributes} that owns this attribute. The entity
054     * might be a {@link BCClass}, {@link BCField}, {@link BCMethod}, or other
055     * attribute.
056     */
057    public Attributes getOwner() {
058        return _owner;
059    }
060
061    /**
062     * Return the index in the {@link ConstantPool} of the {@link UTF8Entry}
063     * holding the name of this attribute.
064     */
065    public int getNameIndex() {
066        return _nameIndex;
067    }
068
069    /**
070     * Return the name of this attribute.
071     */
072    public String getName() {
073        return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue();
074    }
075
076    public Project getProject() {
077        return _owner.getProject();
078    }
079
080    public ConstantPool getPool() {
081        return _owner.getPool();
082    }
083
084    public ClassLoader getClassLoader() {
085        return _owner.getClassLoader();
086    }
087
088    public boolean isValid() {
089        return _owner != null;
090    }
091
092    Collection getAttributesHolder() {
093        return Collections.EMPTY_LIST;
094    }
095
096    /**
097     * Invalidate this attribute.
098     */
099    void invalidate() {
100        _owner = null;
101    }
102
103    /**
104     * Return the length of the bytecode representation of this attribute
105     * in bytes, excluding the name index.
106     */
107    int getLength() {
108        return 0;
109    }
110
111    /**
112     * Copy the information from the given attribute to this one. Does
113     * nothing by default.
114     */
115    void read(Attribute other) {
116    }
117
118    /**
119     * Read the attribute bytecode from the given stream, up to length
120     * bytes, excluding the name index. Does nothing by default.
121     */
122    void read(DataInput in, int length) throws IOException {
123    }
124
125    /**
126     * Write the attribute bytecode to the given stream, up to length bytes,
127     * excluding the name index. Does nothing by default.
128     */
129    void write(DataOutput out, int length) throws IOException {
130    }
131}