1   // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.io.IOException;
6   import java.util.ArrayList;
7   
8   /**
9    * Representation of a class' constant_pool table (JVM Spec Section 4.5). An
10   * instance of CLConstantPool is created when a class is read using CLAbsorber
11   * or constructed using CLEmitter.
12   */
13  
14  class CLConstantPool {
15  
16      // The fields below represent the members of the
17      // constant_pool structure. See JVM Spec Section 4.5 for details.
18  
19      /** Index of the next item into the constant pool. */
20      private int cpIndex;
21  
22      /** List of constant pool items. */
23      private ArrayList<CLCPInfo> cpItems;
24  
25      /**
26       * Look for the specified item in the constant pool. If it exists, return
27       * its index. Otherwise, add the item to the constant pool and return its
28       * (new) index.
29       * 
30       * @param cpInfo
31       *            the item to find or add.
32       * @return index constant pool index of the item.
33       */
34  
35      private int findOrAdd(CLCPInfo cpInfo) {
36          int index = find(cpInfo);
37          if (index == -1) {
38              index = addCPItem(cpInfo);
39          }
40          return index;
41      }
42  
43      /**
44       * Construct a CLConstantPool object.
45       */
46  
47      public CLConstantPool() {
48          cpIndex = 1;
49          cpItems = new ArrayList<CLCPInfo>();
50      }
51  
52      /**
53       * Return the size of the constant pool.
54       * 
55       * @return the size of the constant pool.
56       */
57  
58      public int size() {
59          return cpItems.size();
60      }
61  
62      /**
63       * Return the constant pool index of the specified item if it exists in the
64       * pool, -1 otherwise.
65       * 
66       * @param cpInfo
67       *            item to find.
68       * @return the constant pool index or -1.
69       */
70  
71      public int find(CLCPInfo cpInfo) {
72          int index = cpItems.indexOf(cpInfo);
73          if (index != -1) {
74              CLCPInfo c = cpItems.get(index);
75              index = c.cpIndex;
76          }
77          return index;
78      }
79  
80      /**
81       * Return the constant pool item at the specified index, or null if the
82       * index is invalid.
83       * 
84       * @param i
85       *            constant pool index.
86       * @return the constant pool item or null.
87       */
88  
89      public CLCPInfo cpItem(int i) {
90          if (((i - 1) < 0) || ((i - 1) >= cpItems.size())) {
91              return null;
92          }
93          return cpItems.get(i - 1);
94      }
95  
96      /**
97       * Add the specified (non null) item to the constant pool table and return
98       * its index.
99       * 
100      * @param cpInfo
101      *            the item to add to the constant pool table.
102      * @return constant pool index of the item.
103      */
104 
105     public int addCPItem(CLCPInfo cpInfo) {
106         int i = cpIndex++;
107         cpInfo.cpIndex = i;
108         cpItems.add(cpInfo);
109 
110         // long and double, with their lower and higher words,
111         // are treated by JVM as two items in the constant pool. We
112         // have a single representation for each, so we add a null as
113         // a placeholder in the second slot.
114         if ((cpInfo instanceof CLConstantLongInfo)
115                 || (cpInfo instanceof CLConstantDoubleInfo)) {
116             cpIndex++;
117             cpItems.add(null);
118         }
119         return i;
120     }
121 
122     /**
123      * Write the contents of the constant_pool to the specified output stream.
124      * 
125      * @param out
126      *            output stream.
127      * @throws IOException
128      *             if an error occurs while writing.
129      */
130 
131     public void write(CLOutputStream out) throws IOException {
132         for (int i = 0; i < cpItems.size(); i++) {
133             CLCPInfo cpInfo = cpItems.get(i);
134             if (cpInfo != null) {
135                 cpInfo.write(out);
136             }
137         }
138     }
139 
140     /**
141      * Write the contents of the constant pool to STDOUT in a format similar to
142      * that of javap.
143      * 
144      * @param p
145      *            for pretty printing with indentation.
146      */
147 
148     public void writeToStdOut(PrettyPrinter p) {
149         p.printf("// Constant Pool (%s Items)\n", size());
150         p.printf("%-10s%-20s%s\n", "Index", "Item Type", "Content");
151         p.printf("%-10s%-20s%s\n", "-----", "---------", "-------");
152         for (int i = 1; i <= size(); i++) {
153             CLCPInfo cpInfo = cpItem(i);
154             if (cpInfo != null) {
155                 cpInfo.writeToStdOut(p);
156             }
157         }
158     }
159 
160     // Following methods are helpers for creating singleton
161     // instances of the different constant pool items -- classes extending
162     // CLCPInfo objects in our representation. Each method
163     // accepts as arguments the information needed for creating a
164     // particular contanst pool item, creates an instance
165     // of the item, checks if the item already exists in the
166     // constant pool, adds it if not, and returns the (possibly new) index
167     // of the item.
168 
169     /**
170      * Return the constant pool index of a singleton instance of
171      * CLConstantClassInfo.
172      * 
173      * @param s
174      *            class or interface name in internal form.
175      * @return constant pool index.
176      */
177 
178     public int constantClassInfo(String s) {
179         CLCPInfo c = new CLConstantClassInfo(constantUtf8Info(s));
180         return findOrAdd(c);
181     }
182 
183     /**
184      * Return the constant pool index of a singleton instance of
185      * CLConstantFieldRefInfo.
186      * 
187      * @param className
188      *            class or interface name in internal form.
189      * @param name
190      *            name of the field.
191      * @param type
192      *            descriptor of the field.
193      * @return constant pool index.
194      */
195 
196     public int constantFieldRefInfo(String className, String name, String type) {
197         CLCPInfo c = new CLConstantFieldRefInfo(constantClassInfo(className),
198                 constantNameAndTypeInfo(name, type));
199         return findOrAdd(c);
200     }
201 
202     /**
203      * Return the constant pool index of a singleton instance of
204      * CLConstantMethodRefInfo.
205      * 
206      * @param className
207      *            class or interface name in internal form.
208      * @param name
209      *            name of the method.
210      * @param type
211      *            descriptor of the method.
212      * @return constant pool index.
213      */
214 
215     public int constantMethodRefInfo(String className, String name, String type) {
216         CLCPInfo c = new CLConstantMethodRefInfo(constantClassInfo(className),
217                 constantNameAndTypeInfo(name, type));
218         return findOrAdd(c);
219     }
220 
221     /**
222      * Return the constant pool index of a singleton instance of
223      * CLConstantInterfaceMethodRefInfo.
224      * 
225      * @param className
226      *            class or interface name in internal form.
227      * @param name
228      *            name of the method.
229      * @param type
230      *            descriptor of the method.
231      * @return constant pool index.
232      */
233 
234     public int constantInterfaceMethodRefInfo(String className, String name,
235             String type) {
236         CLCPInfo c = new CLConstantInterfaceMethodRefInfo(
237                 constantClassInfo(className), constantNameAndTypeInfo(name,
238                         type));
239         return findOrAdd(c);
240     }
241 
242     /**
243      * Return the constant pool index of a singleton instance of
244      * CLConstantStringInfo.
245      * 
246      * @param s
247      *            the constant string value.
248      * @return constant pool index.
249      */
250 
251     public int constantStringInfo(String s) {
252         CLCPInfo c = new CLConstantStringInfo(constantUtf8Info(s));
253         return findOrAdd(c);
254     }
255 
256     /**
257      * Return the constant pool index of a singleton instance of
258      * CLConstantIntegerInfo.
259      * 
260      * @param i
261      *            the constant int value.
262      * @return constant pool index.
263      */
264 
265     public int constantIntegerInfo(int i) {
266         CLCPInfo c = new CLConstantIntegerInfo(i);
267         return findOrAdd(c);
268     }
269 
270     /**
271      * Return the constant pool index of a singleton instance of
272      * CLConstantFloatInfo.
273      * 
274      * @param f
275      *            the constant floating-point value.
276      * @return constant pool index.
277      */
278 
279     public int constantFloatInfo(float f) {
280         CLCPInfo c = new CLConstantFloatInfo(f);
281         return findOrAdd(c);
282     }
283 
284     /**
285      * Return the constant pool index of a singleton instance of
286      * CLConstantLongInfo.
287      * 
288      * @param l
289      *            the constant long value.
290      * @return constant pool index.
291      */
292 
293     public int constantLongInfo(long l) {
294         CLCPInfo c = new CLConstantLongInfo(l);
295         return findOrAdd(c);
296     }
297 
298     /**
299      * Return the constant pool index of a singleton instance of
300      * CLConstantDoubleInfo.
301      * 
302      * @param d
303      *            the constant double value.
304      * @return constant pool index.
305      */
306 
307     public int constantDoubleInfo(double d) {
308         CLCPInfo c = new CLConstantDoubleInfo(d);
309         return findOrAdd(c);
310     }
311 
312     /**
313      * Return the constant pool index of a singleton instance of
314      * CLConstantNameAndTypeInfo.
315      * 
316      * @param name
317      *            field or method name.
318      * @param type
319      *            field or method type descriptor.
320      * @return constant pool index.
321      */
322 
323     public int constantNameAndTypeInfo(String name, String type) {
324         CLCPInfo c = new CLConstantNameAndTypeInfo(constantUtf8Info(name),
325                 constantUtf8Info(type));
326         return findOrAdd(c);
327     }
328 
329     /**
330      * Return the constant pool index of a singleton instance of
331      * CLConstantUtf8Info.
332      * 
333      * @param s
334      *            the constant string value.
335      * @return constant pool index.
336      */
337 
338     public int constantUtf8Info(String s) {
339         CLCPInfo c = new CLConstantUtf8Info(s.getBytes());
340         return findOrAdd(c);
341     }
342 
343 }
344