View Javadoc

1   package serp.bytecode.lowlevel;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   import serp.bytecode.visitor.*;
7   
8   /***
9    * Base type for all constant pool entries. Entries should generally be
10   * considered immutable; modifying an entry directly can have dire
11   * consequences, and often renders the resulting class file invalid.
12   *
13   * <p>Entries cannot be shared among constant pools.</p>
14   *
15   * @author Abe White
16   */
17  public abstract class Entry implements VisitAcceptor {
18      public static final int UTF8 = 1;
19      public static final int INT = 3;
20      public static final int FLOAT = 4;
21      public static final int LONG = 5;
22      public static final int DOUBLE = 6;
23      public static final int CLASS = 7;
24      public static final int STRING = 8;
25      public static final int FIELD = 9;
26      public static final int METHOD = 10;
27      public static final int INTERFACEMETHOD = 11;
28      public static final int NAMEANDTYPE = 12;
29      private ConstantPool _pool = null;
30      private int _index = 0;
31  
32      /***
33       * Read a single entry from the given bytecode stream and returns it.
34       */
35      public static Entry read(DataInput in) throws IOException {
36          Entry entry = create(in.readUnsignedByte());
37          entry.readData(in);
38          return entry;
39      }
40  
41      /***
42       * Write the given entry to the given bytecode stream.
43       */
44      public static void write(Entry entry, DataOutput out)
45          throws IOException {
46          out.writeByte(entry.getType());
47          entry.writeData(out);
48      }
49  
50      /***
51       * Create an entry based on its type code.
52       */
53      public static Entry create(int type) {
54          switch (type) {
55          case CLASS:
56              return new ClassEntry();
57          case FIELD:
58              return new FieldEntry();
59          case METHOD:
60              return new MethodEntry();
61          case INTERFACEMETHOD:
62              return new InterfaceMethodEntry();
63          case STRING:
64              return new StringEntry();
65          case INT:
66              return new IntEntry();
67          case FLOAT:
68              return new FloatEntry();
69          case LONG:
70              return new LongEntry();
71          case DOUBLE:
72              return new DoubleEntry();
73          case NAMEANDTYPE:
74              return new NameAndTypeEntry();
75          case UTF8:
76              return new UTF8Entry();
77          default:
78              throw new IllegalArgumentException("type = " + type);
79          }
80      }
81  
82      /***
83       * Return the type code for this entry type.
84       */
85      public abstract int getType();
86  
87      /***
88       * Return true if this is a wide entry -- i.e. if it takes up two
89       * places in the constant pool. Returns false by default.
90       */
91      public boolean isWide() {
92          return false;
93      }
94  
95      /***
96       * Returns the constant pool containing this entry, or null if none.
97       */
98      public ConstantPool getPool() {
99          return _pool;
100     }
101 
102     /***
103      * Returns the index of the entry in the owning constant pool, or 0.
104      */
105     public int getIndex() {
106         return _index;
107     }
108 
109     /***
110      * This method is called after reading the entry type from bytecode.
111      * It should read all the data for this entry from the given stream.
112      */
113     abstract void readData(DataInput in) throws IOException;
114 
115     /***
116      * This method is called after writing the entry type to bytecode.
117      * It should write all data for this entry to the given stream.
118      */
119     abstract void writeData(DataOutput out) throws IOException;
120 
121     /***
122      * Subclasses must call this method before their state is mutated.
123      */
124     Object beforeModify() {
125         if (_pool == null)
126             return null;
127         return _pool.getKey(this);
128     }
129 
130     /***
131      * Subclasses must call this method when their state is mutated.
132      */
133     void afterModify(Object key) {
134         if (_pool != null)
135             _pool.modifyEntry(key, this);
136     }
137 
138     /***
139      * Sets the owning pool of the entry.
140      */
141     void setPool(ConstantPool pool) {
142         // attempting to overwrite current pool?
143         if (_pool != null && pool != null && _pool != pool)
144             throw new IllegalStateException("Entry already belongs to a pool");
145         _pool = pool;
146     }
147 
148     /***
149      * Set the index of this entry within the pool.
150      */
151     void setIndex(int index) {
152         _index = index;
153     }
154 }