View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  
18  package org.apache.jdo.impl.enhancer.classfile;
19  
20  import java.util.Vector;
21  import java.util.Hashtable;
22  import java.io.*;
23  
24  /***
25   *  Constant Pool implementation - this represents the constant pool
26   *  of a class in a class file.
27   */
28  public class ConstantPool implements VMConstants {
29  
30      /* The actual pool */
31      private Vector pool = new Vector();
32  
33      /* uniqifier tables */
34      private boolean hashed = false;
35      private Hashtable utfTable = new Hashtable(11);
36      private Hashtable unicodeTable = new Hashtable(3);
37      private Hashtable stringTable = new Hashtable(11);
38      private Hashtable classTable = new Hashtable(11);
39      private Hashtable intTable = new Hashtable(3);
40      private Hashtable floatTable = new Hashtable(3);
41      private Hashtable longTable = new Hashtable(3);
42      private Hashtable doubleTable = new Hashtable(3);
43  
44      private Vector methodRefTable = new Vector();
45      private Vector fieldRefTable = new Vector();
46      private Vector ifaceMethodRefTable = new Vector();
47      private Vector nameAndTypeTable = new Vector();
48  
49      /* public accessors */
50  
51      /***
52       * Return the number of pool entries.
53       */
54      public int nEntries() {
55          return pool.size();
56      }
57  
58      /***
59       * Return the constant in the pool at the specified entry index
60       */
61      public ConstBasic constantAt (int index) {
62          return (ConstBasic) pool.elementAt(index);
63      }
64  
65      /***
66       * Find or create a class constant in the pool
67       */
68      public ConstClass addClass (String className) {
69          hashConstants();
70          ConstClass c = (ConstClass) classTable.get(className);
71          if (c == null) {
72              c = new ConstClass(addUtf8(className));
73              internConstant(c);
74          }
75          return c;
76      }
77    
78      /***
79       * Find or create a field constant in the pool
80       */
81      public ConstFieldRef addFieldRef (String className, String fieldName,
82                                        String type) {
83          hashConstants();
84          ConstFieldRef f = (ConstFieldRef)
85              searchTable(fieldRefTable, className, fieldName, type);
86  
87          if (f == null) {
88              f = new ConstFieldRef (addClass(className),
89                                     addNameAndType(fieldName, type));
90              internConstant(f);
91          }
92          return f;
93      }
94  
95      /***
96       * Find or create a method constant in the pool
97       */
98      public ConstMethodRef addMethodRef (String className, String methodName,
99                                          String type) {
100         hashConstants();
101         ConstMethodRef m = (ConstMethodRef)
102             searchTable(methodRefTable, className, methodName, type);
103         if (m == null) {
104             m = new ConstMethodRef (addClass(className),
105                                     addNameAndType(methodName, type));
106             internConstant(m);
107         }
108         return m;
109     }
110 
111     /***
112      * Find or create an interface method constant in the pool
113      */
114     public ConstInterfaceMethodRef addInterfaceMethodRef (String className,
115                                                           String methodName, String type) {
116         hashConstants();
117         ConstInterfaceMethodRef m = (ConstInterfaceMethodRef)
118             searchTable(ifaceMethodRefTable, className, methodName, type);
119         if (m == null) {
120             m = new ConstInterfaceMethodRef (addClass(className),
121                                              addNameAndType(methodName, type));
122             internConstant(m);
123         }
124         return m;
125     }
126 
127     /***
128      * Find or create a string constant in the pool
129      */
130     public ConstString addString (String s) {
131         hashConstants();
132         ConstString cs = (ConstString) stringTable.get(s);
133         if (cs == null) {
134             cs = new ConstString(addUtf8(s));
135             internConstant(cs);
136         }
137         return cs;
138     }
139   
140     /***
141      * Find or create an integer constant in the pool
142      */
143     public ConstInteger addInteger (int i) {
144         hashConstants();
145         Integer io = new Integer(i);
146         ConstInteger ci = (ConstInteger) intTable.get(io);
147         if (ci == null) {
148             ci = new ConstInteger(i);
149             internConstant(ci);
150         }
151         return ci;
152     }
153   
154     /***
155      * Find or create a float constant in the pool
156      */
157     public ConstFloat addFloat (float f) {
158         hashConstants();
159         Float fo = new Float(f);
160         ConstFloat cf = (ConstFloat) floatTable.get(fo);
161         if (cf == null) {
162             cf = new ConstFloat(f);
163             internConstant(cf);
164         }
165         return cf;
166     }
167   
168     /***
169      * Find or create a long constant in the pool
170      */
171     public ConstLong addLong (long l) {
172         hashConstants();
173         Long lo = new Long(l);
174         ConstLong cl = (ConstLong) longTable.get(lo);
175         if (cl == null) {
176             cl = new ConstLong(l);
177             internConstant(cl);
178             internConstant(null);
179         }
180         return cl;
181     }
182   
183     /***
184      * Find or create a double constant in the pool
185      */
186     public ConstDouble addDouble (double d) {
187         hashConstants();
188         Double dobj = new Double(d);
189         ConstDouble cd = (ConstDouble) doubleTable.get(dobj);
190         if (cd == null) {
191             cd = new ConstDouble(d);
192             internConstant(cd);
193             internConstant(null);
194         }
195         return cd;
196     }
197   
198     /***
199      * Find or create a name/type constant in the pool
200      */
201     public ConstNameAndType addNameAndType (String name, String type) {
202         hashConstants();
203         for (int i=0; i<nameAndTypeTable.size(); i++) {
204             ConstNameAndType nt = (ConstNameAndType) nameAndTypeTable.elementAt(i);
205             if (nt.name().asString().equals(name) &&
206                 nt.signature().asString().equals(type))
207                 return nt;
208         }
209 
210         ConstNameAndType nt =
211             new ConstNameAndType(addUtf8(name), addUtf8(type));
212         internConstant(nt);
213         return nt;
214     }
215 
216     /***
217      * Find or create a utf8 constant in the pool
218      */
219     public ConstUtf8 addUtf8 (String s) {
220         hashConstants();
221         ConstUtf8 u = (ConstUtf8) utfTable.get(s);
222         if (u == null) {
223             u = new ConstUtf8(s);
224             internConstant(u);
225         }
226         return u;
227     }
228 
229     /***
230      * Find or create a unicode constant in the pool
231      * Obsolete?
232      */
233     public ConstUnicode addUnicode (String s) {
234         hashConstants();
235         ConstUnicode u = (ConstUnicode) unicodeTable.get(s);
236         if (u == null) {
237             u = new ConstUnicode(s);
238             internConstant(u);
239         }
240         return u;
241     }
242 
243     /* package local methods *//package-summary/html">class="comment"> package local methods *//package-summary.html">/* package local methods *//package-summary.html">class="comment"> package local methods */
244 
245     ConstantPool() {
246         pool.addElement(null);
247     }
248 
249     ConstantPool(DataInputStream input) throws IOException {
250         pool.addElement(null);
251         int nconstants = input.readUnsignedShort()-1;
252         while (nconstants > 0)
253             nconstants -= readConstant(input);
254 
255         resolvePool();
256     }
257 
258     //@olsen: added 'indent' parameter
259     void print(PrintStream out, int indent) {
260         for (int i=0; i<pool.size(); i++) {
261             ConstBasic c = constantAt(i);
262             if (c != null) {
263                 ClassPrint.spaces(out, indent);
264                 out.print(i);
265                 out.print(": ");
266                 out.println(c.toString());
267             }
268         }
269     }
270 
271     //@olsen: added 'out' and 'indent' parameters
272     void summarize(PrintStream out, int indent) {
273         int stringSize = 0;
274         int nStrings = 0;
275         for (int i=0; i<pool.size(); i++) {
276             ConstBasic c = constantAt(i);
277             if (c != null && c.tag() == CONSTANTUtf8) {
278                 ConstUtf8 utf8 = (ConstUtf8) c;
279                 stringSize += utf8.asString().length();
280                 nStrings++;
281             }
282         }
283         ClassPrint.spaces(out, indent);
284         out.println("" + nStrings + " constant pool strings totalling " + 
285                     stringSize + " bytes");
286     }
287 
288     void write (DataOutputStream buff) throws IOException {
289         buff.writeShort(pool.size());
290         for (int i=1; i<pool.size(); i++) {
291             ConstBasic cb = (ConstBasic) pool.elementAt(i);
292             if (cb != null) {
293                 buff.writeByte((byte) cb.tag());
294                 cb.formatData(buff);
295             }
296         }
297     }
298 
299     /* private methods */
300 
301     private void resolvePool() {
302         /* resolve indexes to object references */
303         for (int i=0; i<pool.size(); i++) {
304             ConstBasic c = constantAt(i);
305             if (c != null) {
306                 c.setIndex(i);
307                 c.resolve(this);
308             }
309         }
310     }
311 
312     private void hashConstants() {
313         if (hashed)
314             return;
315 
316         /* Enter objects into the hash tables */
317         for (int j=0; j<pool.size(); j++) {
318             ConstBasic c = constantAt(j);
319             if (c != null) {
320                 recordConstant(c);
321             }
322         }
323 
324         hashed = true;
325     }
326 
327     /* returns the number of slots used */
328     private int readConstant(DataInputStream input) throws IOException {
329         ConstBasic basic;
330         byte b = input.readByte();
331         int slots = 1;
332         switch (b) {
333         case CONSTANTUtf8:
334             basic = ConstUtf8.read(input);
335             break;
336         case CONSTANTUnicode:
337             basic = ConstUnicode.read(input);
338             break;
339         case CONSTANTInteger:
340             basic = ConstInteger.read(input);
341             break;
342         case CONSTANTFloat:
343             basic = ConstFloat.read(input);
344             break;
345         case CONSTANTLong:
346             basic = ConstLong.read(input);
347             slots = 2;
348             break;
349         case CONSTANTDouble:
350             basic = ConstDouble.read(input);
351             slots = 2;
352             break;
353         case CONSTANTClass:
354             basic = ConstClass.read(input);
355             break;
356         case CONSTANTString:
357             basic = ConstString.read(input);
358             break;
359         case CONSTANTFieldRef:
360             basic = ConstFieldRef.read(input);
361             break;
362         case CONSTANTMethodRef:
363             basic = ConstMethodRef.read(input);
364             break;
365         case CONSTANTInterfaceMethodRef:
366             basic = ConstInterfaceMethodRef.read(input);
367             break;
368         case CONSTANTNameAndType:
369             basic = ConstNameAndType.read(input);
370             break;
371         default:
372             throw new ClassFormatError("Don't know this constant type: " +
373                                        Integer.toString(b));
374         }
375 
376         pool.addElement(basic);
377         if (slots > 1)
378             pool.addElement(null);   
379         return slots;
380     }
381 
382     private void internConstant (ConstBasic c) {
383         if (c != null) {
384             c.setIndex(pool.size());
385             recordConstant(c);
386         }
387         pool.addElement(c);
388     }
389 
390     private void recordConstant (ConstBasic c) {
391         if (c != null) {
392             switch (c.tag()) {
393             case CONSTANTUtf8:
394                 utfTable.put(((ConstUtf8)c).asString(), c);
395                 break;
396             case CONSTANTUnicode:
397                 unicodeTable.put(((ConstUnicode)c).asString(), c);
398                 break;
399             case CONSTANTInteger:
400                 intTable.put(new Integer(((ConstInteger)c).value()), c);
401                 break;
402             case CONSTANTFloat:
403                 floatTable.put(new Float(((ConstFloat)c).value()), c);
404                 break;
405             case CONSTANTLong:
406                 longTable.put(new Long(((ConstLong)c).value()), c);
407                 break;
408             case CONSTANTDouble:
409                 doubleTable.put(new Double(((ConstDouble)c).value()), c);
410                 break;
411             case CONSTANTClass:
412                 classTable.put(((ConstClass)c).asString(), c);
413                 break;
414             case CONSTANTString:
415                 stringTable.put(((ConstString)c).value().asString(), c);
416                 break;
417             case CONSTANTFieldRef:
418                 fieldRefTable.addElement(c);
419                 break;
420             case CONSTANTMethodRef:
421                 methodRefTable.addElement(c);
422                 break;
423             case CONSTANTInterfaceMethodRef:
424                 ifaceMethodRefTable.addElement(c);
425                 break;
426             case CONSTANTNameAndType:
427                 nameAndTypeTable.addElement(c);
428                 break;
429             }
430         }
431     }
432 
433     private ConstBasicMemberRef searchTable(Vector table, String cname,
434                                             String mname, String sig) {
435         for (int i=0; i<table.size(); i++) {
436             ConstBasicMemberRef memRef = (ConstBasicMemberRef) table.elementAt(i);
437             if (memRef.className().asString().equals(cname) &&
438                 memRef.nameAndType().name().asString().equals(mname) &&
439                 memRef.nameAndType().signature().asString().equals(sig))
440                 return memRef;
441         }
442         return null;
443     }
444 }