View Javadoc

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