View Javadoc

1   // jq_ConstantPool.java, created Fri Jan 11 17:29:36 2002 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Class;
5   
6   import java.util.Arrays;
7   import java.util.HashMap;
8   import java.util.Iterator;
9   import java.util.LinkedList;
10  import java.util.Map;
11  import java.util.Set;
12  import java.io.DataInput;
13  import java.io.DataOutput;
14  import java.io.IOException;
15  import joeq.Compiler.BytecodeAnalysis.Bytecodes;
16  import joeq.Runtime.Debug;
17  import joeq.Runtime.Reflection;
18  import joeq.UTF.Utf8;
19  import jwutil.util.Assert;
20  
21  /***
22   * jq_ConstantPool
23   * 
24   * @author  John Whaley <jwhaley@alum.mit.edu>
25   * @version $Id: jq_ConstantPool.java 2073 2004-12-10 10:55:02Z joewhaley $
26   */
27  public class jq_ConstantPool implements jq_ClassFileConstants {
28  
29      public static /*final*/ boolean TRACE = false;
30  
31      private Object[] constant_pool;
32      private byte[] constant_pool_tags;
33      
34      /*** Creates new jq_ConstantPool */
35      public jq_ConstantPool(int size) {
36          constant_pool = new Object[size];
37          constant_pool_tags = new byte[size];
38      }
39  
40      public String toString() {
41          return Arrays.asList(constant_pool).toString();
42      }
43  
44      public void load(DataInput in) throws IOException, ClassFormatError {
45          // first pass: read in the constant pool
46          int constant_pool_count = constant_pool.length;
47          for (int i=1; i<constant_pool_count; ++i) { // CP slot 0 is unused
48              switch (constant_pool_tags[i] = in.readByte()) {
49              case CONSTANT_Integer:
50                  constant_pool[i] = new Integer(in.readInt());
51                  break;
52              case CONSTANT_Float:
53                  constant_pool[i] = new Float(in.readFloat());
54                  break;
55              case CONSTANT_Long:
56                  constant_pool[i++] = new Long(in.readLong());
57                  break;
58              case CONSTANT_Double:
59                  constant_pool[i++] = new Double(in.readDouble());
60                  break;
61              case CONSTANT_Utf8: {
62                  byte utf[] = new byte[in.readUnsignedShort()];
63                  in.readFully(utf);
64                  constant_pool[i] = Utf8.get(utf);
65                  break; }
66              case CONSTANT_Class:
67              case CONSTANT_String:
68                  // resolved on the next pass
69                  constant_pool[i] = new Character((char)in.readUnsignedShort()); // freed later
70                  break;
71              case CONSTANT_NameAndType:
72              case CONSTANT_FieldRef:
73              case CONSTANT_MethodRef:
74              case CONSTANT_InterfaceMethodRef: {
75                  // resolved on the next pass
76                  char class_index = (char)in.readUnsignedShort();
77                  char name_and_type_index = (char)in.readUnsignedShort();
78                  constant_pool[i] = new PairOfChars(class_index, name_and_type_index); // freed later
79                  break; }
80              default:
81                  throw new ClassFormatError("bad constant pool entry tag (entry="+i+", tag="+constant_pool_tags[i]);
82              }
83          }
84      }
85      
86      static class PairOfChars {
87          char c1, c2;
88          PairOfChars(char c1, char c2) { this.c1 = c1; this.c2 = c2; }
89          char getFirst() { return c1; }
90          char getSecond() { return c2; }
91      }
92      
93      public void resolve(ClassLoader cl) {
94          // second pass: resolve the non-primitive stuff
95          int constant_pool_count = constant_pool.length;
96          for (int i=1; i<constant_pool_count; ++i) { // CP slot 0 is unused
97              switch (constant_pool_tags[i]) {
98              case CONSTANT_Integer:
99              case CONSTANT_Float:
100             case CONSTANT_Utf8:
101                 break;
102             case CONSTANT_Long:
103             case CONSTANT_Double:
104                 ++i;
105                 // do nothing, already resolved
106                 break;
107             case CONSTANT_NameAndType:
108                 // skipped
109                 break;
110             case CONSTANT_Class:
111                 resolveClass(cl, i);
112                 break;
113             case CONSTANT_ResolvedClass:
114                 // already forward resolved.
115                 break;
116             case CONSTANT_String:
117                 char string_index = ((Character)constant_pool[i]).charValue();
118                 if (constant_pool_tags[string_index] != CONSTANT_Utf8)
119                     throw new ClassFormatError("constant pool entry "+(int)string_index+", referred to by "+i+
120                                                ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+constant_pool_tags[string_index]+")");
121                 Utf8 string = (Utf8)constant_pool[string_index];
122                 // free (constant_pool[i])
123                 constant_pool[i] = string.toString();
124                 break;
125             case CONSTANT_FieldRef:
126             case CONSTANT_MethodRef:
127             case CONSTANT_InterfaceMethodRef: {
128                 PairOfChars pair = (PairOfChars)constant_pool[i];
129                 char class_index = pair.getFirst();
130                 char name_and_type_index = pair.getSecond();
131                 if (constant_pool_tags[class_index] != CONSTANT_ResolvedClass) {
132                     if (constant_pool_tags[class_index] != CONSTANT_Class)
133                         throw new ClassFormatError("constant pool entry "+(int)class_index+", referred to by "+i+
134                                                    ", is wrong type tag (expected="+CONSTANT_Class+", actual="+constant_pool_tags[class_index]+")");
135                     if (class_index > i) {
136                         // forward class reference, resolve it now.
137                         resolveClass(cl, class_index);
138                     }
139                 } else {
140                     // already resolved.
141                 }
142                 // note: javac 1.5 can generate array references here. yuck.
143                 jq_Reference r = (jq_Reference) constant_pool[class_index];
144                 jq_Class clazz;
145                 if (r instanceof jq_Class)
146                     clazz = (jq_Class) r;
147                 else
148                     clazz = PrimordialClassLoader.getJavaLangObject();
149                 PairOfChars pair2 = (PairOfChars)constant_pool[name_and_type_index];
150                 char name_index = pair2.getFirst();
151                 char desc_index = pair2.getSecond();
152                 if (constant_pool_tags[name_index] != CONSTANT_Utf8)
153                     throw new ClassFormatError("constant pool entry "+(int)name_index+", referred to by "+(int)name_and_type_index+
154                                                ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+constant_pool_tags[name_index]+")");
155                 if (constant_pool_tags[desc_index] != CONSTANT_Utf8)
156                     throw new ClassFormatError("constant pool entry "+(int)desc_index+", referred to by "+(int)name_and_type_index+
157                                                ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+constant_pool_tags[desc_index]+")");
158                 Utf8 name = (Utf8)constant_pool[name_index];
159                 Utf8 desc = (Utf8)constant_pool[desc_index];
160                 if (constant_pool_tags[i] == CONSTANT_FieldRef) {
161                     if (!desc.isValidTypeDescriptor())
162                         throw new ClassFormatError(desc+" is not a valid type descriptor");
163                 } else {
164                     if (!desc.isValidMethodDescriptor())
165                         throw new ClassFormatError(desc+" is not a valid method descriptor");
166                 }
167                 jq_NameAndDesc nd = new jq_NameAndDesc(name, desc);
168                 // free (constant_pool[i])
169                 if (clazz.isLoaded()) {
170                     jq_Member mem = clazz.getDeclaredMember(nd);
171                     if (mem == null) {
172                         // this constant pool entry refers to a member that doesn't exist in the named class.
173                         if (TRACE) Debug.writeln("No such member: "+clazz+"."+nd+", referenced by cp idx "+(int)i);
174                         if (false) {
175                             // throw resolution exception early
176                             String s = ("No such member: "+clazz+"."+nd+", referenced by cp idx "+(int)i);
177                             if (constant_pool_tags[i] == CONSTANT_FieldRef)
178                                 throw new NoSuchFieldError(s);
179                             else
180                                 throw new NoSuchMethodError(s);
181                         } else {
182                             // NoSuchFieldError/NoSuchMethodError should be thrown when this member is resolved.
183                             constant_pool[i] = new jq_MemberReference(clazz, nd);
184                         }
185                     } else {
186                         constant_pool[i] = mem;
187                         if (desc.isDescriptor(TC_PARAM)) {
188                             if (mem.isStatic()) {
189                                 constant_pool_tags[i] = CONSTANT_ResolvedSMethodRef;
190                                 if (TRACE) Debug.writeln("Resolved static method "+mem+", cp idx "+(int)i);
191                             } else {
192                                 constant_pool_tags[i] = CONSTANT_ResolvedIMethodRef;
193                                 if (TRACE) Debug.writeln("Resolved instance method "+mem+", cp idx "+(int)i);
194                             }
195                         } else {
196                             if (mem.isStatic()) {
197                                 constant_pool_tags[i] = CONSTANT_ResolvedSFieldRef;
198                                 if (TRACE) Debug.writeln("Resolved static field "+mem+", cp idx "+(int)i);
199                             } else {
200                                 constant_pool_tags[i] = CONSTANT_ResolvedIFieldRef;
201                                 if (TRACE) Debug.writeln("Resolved instance field "+mem+", cp idx "+(int)i);
202                             }
203                         }
204                     }
205                 } else {
206                     constant_pool[i] = new jq_MemberReference(clazz, nd);
207                 }
208                 break; }
209             default:
210                 Assert.UNREACHABLE();
211                 return;
212             }
213         }
214     }
215 
216     private void resolveClass(ClassLoader cl, int i) throws ClassFormatError {
217         char name_index = ((Character)constant_pool[i]).charValue();
218         if (constant_pool_tags[name_index] != CONSTANT_Utf8)
219             throw new ClassFormatError("constant pool entry "+name_index+", referred to by "+i+
220                                        ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+constant_pool_tags[name_index]);
221         Utf8 classname = (Utf8)constant_pool[name_index];
222         // free (constant_pool[i])
223         if (!classname.isDescriptor(TC_ARRAY)) {
224             classname = classname.getAsClassDescriptor();
225         }
226         constant_pool[i] = PrimordialClassLoader.getOrCreateType(cl, classname);
227         constant_pool_tags[i] = CONSTANT_ResolvedClass;
228         if (TRACE) Debug.writeln("Resolved class "+constant_pool[i]+", cp idx "+(int)i);
229     }
230 
231     public final void set(char index, Object o, byte tag) {
232         constant_pool[index] = o;
233         constant_pool_tags[index] = tag;
234     }
235 
236     public final int getCount() {
237         return constant_pool.length;
238     }
239     public final byte getTag(char index) {
240         return constant_pool_tags[index];
241     }
242     public final Object get(char index) {
243         return constant_pool[index];
244     }
245     public final Integer getAsInt(char index) {
246         Assert._assert(constant_pool_tags[index] == CONSTANT_Integer);
247         return (Integer)constant_pool[index];
248     }
249     public final Float getAsFloat(char index) {
250         Assert._assert(constant_pool_tags[index] == CONSTANT_Float);
251         return (Float)constant_pool[index];
252     }
253     public final Long getAsLong(char index) {
254         Assert._assert(constant_pool_tags[index] == CONSTANT_Long);
255         return (Long)constant_pool[index];
256     }
257     public final Double getAsDouble(char index) {
258         Assert._assert(constant_pool_tags[index] == CONSTANT_Double);
259         return (Double)constant_pool[index];
260     }
261     public final String getAsString(char index) {
262         Assert._assert(constant_pool_tags[index] == CONSTANT_String);
263         return (String)constant_pool[index];
264     }
265     public final Utf8 getAsUtf8(char index) {
266         Assert._assert(constant_pool_tags[index] == CONSTANT_Utf8);
267         return (Utf8)constant_pool[index];
268     }
269     public final jq_Type getAsType(char index) {
270         Assert._assert(constant_pool_tags[index] == CONSTANT_ResolvedClass);
271         return (jq_Type)constant_pool[index];
272     }
273     public final Object getAsObjectConstant(char index) {
274         byte c = constant_pool_tags[index];
275         Object o = constant_pool[index];
276         Assert._assert(c == CONSTANT_String || c == CONSTANT_ResolvedClass);
277         if (c == CONSTANT_ResolvedClass) {
278             o = Reflection.getJDKType((jq_Reference) o);
279         }
280         return o;
281     }
282     public final jq_Member getAsMember(char index) {
283         Assert._assert(constant_pool_tags[index] == CONSTANT_ResolvedSFieldRef ||
284                   constant_pool_tags[index] == CONSTANT_ResolvedIFieldRef ||
285                   constant_pool_tags[index] == CONSTANT_ResolvedSMethodRef ||
286                   constant_pool_tags[index] == CONSTANT_ResolvedIMethodRef);
287         return (jq_Member)constant_pool[index];
288     }
289     public final jq_StaticField getAsStaticField(char index) {
290         if (constant_pool_tags[index] == CONSTANT_ResolvedSFieldRef)
291             return (jq_StaticField)constant_pool[index];
292         if (constant_pool_tags[index] != CONSTANT_FieldRef)
293             throw new VerifyError();
294         if (TRACE) Debug.writeln("Attempting to resolve static field "+constant_pool[index]+" cp idx "+(int)index);
295         jq_MemberReference n = (jq_MemberReference)constant_pool[index];
296         jq_Class otherclazz = n.getReferencedClass();
297         jq_NameAndDesc nd = n.getNameAndDesc();
298         if (otherclazz.isInClassLib())
299             nd = joeq.ClassLib.ClassLibInterface.convertClassLibNameAndDesc(otherclazz, nd);
300         jq_StaticField f;
301         if (otherclazz.isLoaded()) {
302             f = otherclazz.getStaticField(nd);
303             if (f == null) 
304                 throw new NoSuchFieldError("no such static field "+otherclazz+"."+nd);
305         } else {
306             // we differ slightly from the vm spec in that when a reference to the member is
307             // encountered before the class is loaded, and the member is actually in a
308             // superclass/superinterface it will throw a NoSuchFieldError when the member is
309             // accessed.
310             // Java compilers don't generate such references, unless class files are old.
311             jq_Field m = (jq_Field)otherclazz.getDeclaredMember(nd);
312             if (m == null) {
313                 constant_pool[index] = f = otherclazz.createStaticField(nd);
314                 constant_pool_tags[index] = CONSTANT_ResolvedSFieldRef;
315                 if (TRACE) Debug.writeln("Resolved static field "+f+", cp idx "+(int)index);
316             } else if (!m.isStatic())
317                 throw new VerifyError("field "+m+" referred to as both static and instance");
318             else
319                 f = (jq_StaticField)m;
320         }
321         return f;
322     }
323     public final jq_InstanceField getAsInstanceField(char index) {
324         if (constant_pool_tags[index] == CONSTANT_ResolvedIFieldRef)
325             return (jq_InstanceField)constant_pool[index];
326         if (constant_pool_tags[index] != CONSTANT_FieldRef)
327             throw new VerifyError();
328         if (TRACE) Debug.writeln("Attempting to resolve instance field "+constant_pool[index]+" cp idx "+(int)index);
329         jq_MemberReference n = (jq_MemberReference)constant_pool[index];
330         jq_Class otherclazz = n.getReferencedClass();
331         jq_NameAndDesc nd = n.getNameAndDesc();
332         if (otherclazz.isInClassLib())
333             nd = joeq.ClassLib.ClassLibInterface.convertClassLibNameAndDesc(otherclazz, nd);
334         jq_InstanceField f;
335         if (otherclazz.isLoaded()) {
336             f = otherclazz.getInstanceField(nd);
337             if (f == null) 
338                 throw new NoSuchFieldError("no such instance field "+otherclazz+"."+nd);
339         } else {
340             // we differ slightly from the vm spec in that when a reference to the member is
341             // encountered before the class is loaded, and the member is actually in a
342             // superclass/superinterface it will throw a NoSuchFieldError when the member is
343             // accessed.
344             // Java compilers don't generate such references, unless class files are old.
345             jq_Field m = (jq_Field)otherclazz.getDeclaredMember(nd);
346             if (m == null) {
347                 constant_pool[index] = f = otherclazz.createInstanceField(nd);
348                 constant_pool_tags[index] = CONSTANT_ResolvedIFieldRef;
349                 if (TRACE) Debug.writeln("Resolved instance field "+f+", cp idx "+(int)index);
350             } else if (m.isStatic())
351                 throw new VerifyError("field "+m+" referred to as both static and instance");
352             else
353                 f = (jq_InstanceField)m;
354         }
355         return f;
356     }
357     public final jq_StaticMethod getAsStaticMethod(char index) {
358         if (constant_pool_tags[index] == CONSTANT_ResolvedSMethodRef)
359             return (jq_StaticMethod)constant_pool[index];
360         if (constant_pool_tags[index] != CONSTANT_MethodRef)
361             throw new VerifyError();
362         if (TRACE) Debug.writeln("Attempting to resolve static method "+constant_pool[index]+" cp idx "+(int)index);
363         jq_MemberReference n = (jq_MemberReference)constant_pool[index];
364         jq_Class otherclazz = n.getReferencedClass();
365         jq_NameAndDesc nd = n.getNameAndDesc();
366         if (otherclazz.isInClassLib())
367             nd = joeq.ClassLib.ClassLibInterface.convertClassLibNameAndDesc(otherclazz, nd);
368         jq_StaticMethod f;
369         if (otherclazz.isLoaded()) {
370             f = otherclazz.getStaticMethod(nd);
371             if (f == null) 
372                 throw new NoSuchMethodError("no such static method "+otherclazz+"."+nd);
373         } else {
374             // we differ slightly from the vm spec in that when a reference to the member is
375             // encountered before the class is loaded, and the member is actually in a
376             // superclass/superinterface it will throw a NoSuchFieldError when the member is
377             // accessed.
378             // Java compilers don't generate such references, unless class files are old.
379             jq_Method m = (jq_Method)otherclazz.getDeclaredMember(nd);
380             if (m == null) {
381                 constant_pool[index] = f = otherclazz.createStaticMethod(nd);
382                 constant_pool_tags[index] = CONSTANT_ResolvedSMethodRef;
383                 if (TRACE) Debug.writeln("Resolved static method "+f+", cp idx "+(int)index);
384             } else if (!m.isStatic())
385                 throw new VerifyError("method "+m+" referred to as both static and instance");
386             else
387                 f = (jq_StaticMethod)m;
388         }
389         return f;
390     }
391     public final jq_InstanceMethod getAsInstanceMethod(char index) {
392         if (constant_pool_tags[index] == CONSTANT_ResolvedIMethodRef)
393             return (jq_InstanceMethod)constant_pool[index];
394         if (constant_pool_tags[index] != CONSTANT_MethodRef &&
395             constant_pool_tags[index] != CONSTANT_InterfaceMethodRef)
396             throw new VerifyError();
397         if (TRACE) Debug.writeln("Attempting to resolve instance method "+constant_pool[index]+" cp idx "+(int)index);
398         jq_MemberReference n = (jq_MemberReference)constant_pool[index];
399         jq_Class otherclazz = n.getReferencedClass();
400         jq_NameAndDesc nd = n.getNameAndDesc();
401         if (otherclazz.isInClassLib())
402             nd = joeq.ClassLib.ClassLibInterface.convertClassLibNameAndDesc(otherclazz, nd);
403         jq_InstanceMethod f;
404         if (otherclazz.isLoaded()) {
405             f = otherclazz.getInstanceMethod(nd);
406             if (f == null) 
407                 throw new NoSuchMethodError("no such instance method "+otherclazz+"."+nd);
408         } else {
409             // we differ slightly from the vm spec in that when a reference to the member is
410             // encountered before the class is loaded, and the member is actually in a
411             // superclass/superinterface it will throw a NoSuchFieldError when the member is
412             // accessed.
413             // Java compilers don't generate such references, unless class files are old.
414             jq_Method m = (jq_Method)otherclazz.getDeclaredMember(nd);
415             if (m == null) {
416                 constant_pool[index] = f = otherclazz.createInstanceMethod(nd);
417                 constant_pool_tags[index] = CONSTANT_ResolvedIMethodRef;
418                 if (TRACE) Debug.writeln("Resolved instance method "+f+", cp idx "+(int)index);
419             } else if (m.isStatic())
420                 throw new VerifyError("method "+m+" referred to as both static and instance");
421             else
422                 f = (jq_InstanceMethod)m;
423         }
424         return f;
425     }
426 
427     public void trim(Set/*<jq_Field>*/ necessaryFields, Set/*<jq_Method>*/ necessaryMethods) {
428         for (int i=0; i<constant_pool.length; ++i) {
429             byte cpt = constant_pool_tags[i];
430             Object cpe = constant_pool[i];
431             switch (cpt) {
432                 case CONSTANT_ResolvedSFieldRef:
433                 case CONSTANT_ResolvedIFieldRef:
434                     if (!necessaryFields.contains(cpe)) {
435                         jq_MemberReference mr = new jq_MemberReference(((jq_Member)cpe).getDeclaringClass(), ((jq_Member)cpe).getNameAndDesc());
436                         constant_pool[i] = mr;
437                         constant_pool_tags[i] = CONSTANT_FieldRef;
438                     }
439                     break;
440                 case CONSTANT_ResolvedSMethodRef:
441                 case CONSTANT_ResolvedIMethodRef:
442                     if (!necessaryMethods.contains(cpe)) {
443                         jq_MemberReference mr = new jq_MemberReference(((jq_Member)cpe).getDeclaringClass(), ((jq_Member)cpe).getNameAndDesc());
444                         constant_pool[i] = mr;
445                          // MethodRef and InterfaceMethodRef are treated as equivalent.
446                         constant_pool_tags[i] = CONSTANT_MethodRef;
447                     }
448                     break;
449             }
450         }
451     }
452     
453     public char findEqual(Object o, byte tag) {
454         for (char i=1; i<constant_pool.length; ++i) {
455             if (constant_pool_tags[i] == tag && constant_pool[i].equals(o))
456                 return i;
457         }
458         return 0;
459     }
460 
461     public boolean contains(Object o) {
462         for (int i=0; i<constant_pool.length; ++i) {
463             if (constant_pool[i] == o)
464                 return true;
465         }
466         return false;
467     }
468     
469     private int growCPbyOne() {
470         int newsize = constant_pool.length+1;
471         Object[] newcp = new Object[newsize];
472         System.arraycopy(constant_pool, 0, newcp, 0, constant_pool.length);
473         byte[] newcptags = new byte[newsize];
474         System.arraycopy(constant_pool_tags, 0, newcptags, 0, constant_pool_tags.length);
475         constant_pool = newcp; constant_pool_tags = newcptags;
476         return newsize-1;
477     }
478     
479     public int addInteger(int value) {
480         int index = growCPbyOne();
481         constant_pool[index] = new Integer(value);
482         constant_pool_tags[index] = CONSTANT_Integer;
483         return index;
484     }
485     public int addFloat(float value) {
486         int index = growCPbyOne();
487         constant_pool[index] = new Float(value);
488         constant_pool_tags[index] = CONSTANT_Float;
489         return index;
490     }
491     public int addLong(float value) {
492         int index = growCPbyOne();
493         constant_pool[index] = new Float(value);
494         constant_pool_tags[index] = CONSTANT_Float;
495         growCPbyOne();
496         return index;
497     }
498     public int addDouble(double value) {
499         int index = growCPbyOne();
500         constant_pool[index] = new Double(value);
501         constant_pool_tags[index] = CONSTANT_Double;
502         growCPbyOne();
503         return index;
504     }
505     public int addString(String value) {
506         int index = growCPbyOne();
507         constant_pool[index] = value;
508         constant_pool_tags[index] = CONSTANT_String;
509         return index;
510     }
511     
512     Adder getAdder() { return new Adder(); }
513     
514     class Adder {
515         LinkedList toadd_cp = new LinkedList();
516         
517         public char add(Object o, byte tag) {
518             int i;
519             for (i=0; i<constant_pool.length; ++i) {
520                 if (o.equals(get((char)i))) {
521                     Assert._assert(getTag((char)i) == tag);
522                     return (char)i;
523                 }
524             }
525             ConstantPoolEntry cpe = new ConstantPoolEntry(o, tag);
526             //Iterator it = toadd_cp.iterator();
527             i = toadd_cp.indexOf(cpe);
528             if (i != -1) return (char)i;
529             i = constant_pool.length + toadd_cp.size();
530             toadd_cp.add(cpe);
531  
532             Assert._assert(i <= Character.MAX_VALUE);
533             return (char)i;
534         }
535         
536         public void finish() {
537             if (toadd_cp.size() == 0) return;
538             
539             Object[] new_cp = new Object[constant_pool.length+toadd_cp.size()];
540             byte[] new_cptag = new byte[new_cp.length];
541             int i = constant_pool.length-1;
542             System.arraycopy(constant_pool, 0, new_cp, 0, constant_pool.length);
543             System.arraycopy(constant_pool_tags, 0, new_cptag, 0, constant_pool_tags.length);
544             for (Iterator it = toadd_cp.iterator(); it.hasNext();) {
545                 ConstantPoolEntry cpe = (ConstantPoolEntry)it.next();
546                 new_cp[++i] = cpe.o;
547                 new_cptag[i] = cpe.tag;
548             }
549             constant_pool = new_cp;
550             constant_pool_tags = new_cptag;
551         }
552     }
553 
554     static class ConstantPoolEntry {
555         Object o; byte tag;
556         ConstantPoolEntry(Object o, byte tag) { this.o = o; this.tag = tag; }
557         public boolean equals(ConstantPoolEntry that) {
558             return this.o == that.o && this.tag == that.tag;
559         }
560         public boolean equals(Object that) {
561             if (that instanceof ConstantPoolEntry)
562                 return equals((ConstantPoolEntry)that);
563             return false;
564         }
565         public int hashCode() { return o.hashCode(); }
566     }
567     
568     public static class ConstantPoolRebuilder {
569         HashMap new_entries = new HashMap();
570 
571         private int renumber() {
572             int j = 0;
573             Set entrySet = new_entries.entrySet();
574             Iterator i = entrySet.iterator();
575             while (i.hasNext()) {
576                 Map.Entry e = (Map.Entry)i.next();
577                 Assert._assert(j < Character.MAX_VALUE);
578                 e.setValue(new Character((char)(++j)));
579                 if ((e.getKey() instanceof Long) ||
580                     (e.getKey() instanceof Double))
581                     ++j;
582             }
583             if (TRACE) Debug.writeln("After renumbering constant pool: "+(j+1)+" entries.");
584             return j+1;
585         }
586 
587         public jq_ConstantPool finish() {
588             if (TRACE) Debug.writeln("Finishing rebuilding constant pool...");
589             int cp_size = renumber();
590             int j = 0;
591             Assert._assert(cp_size <= Character.MAX_VALUE);
592             jq_ConstantPool newcp = new jq_ConstantPool(cp_size);
593             Set entrySet = new_entries.entrySet();
594             Iterator i = entrySet.iterator();
595             while (i.hasNext()) {
596                 Map.Entry e = (Map.Entry)i.next();
597                 Object o = e.getKey();
598                 char index = ((Character)e.getValue()).charValue();
599                 ++j; Assert._assert(index == j, (int)index + "!=" + (int)j);
600                 newcp.constant_pool[j] = o;
601                 if (o instanceof Utf8) {
602                     newcp.constant_pool_tags[j] = CONSTANT_Utf8;
603                 } else if (o instanceof Integer) {
604                     newcp.constant_pool_tags[j] = CONSTANT_Integer;
605                 } else if (o instanceof Float) {
606                     newcp.constant_pool_tags[j] = CONSTANT_Float;
607                 } else if (o instanceof Long) {
608                     newcp.constant_pool_tags[j] = CONSTANT_Long;
609                     ++j;
610                 } else if (o instanceof Double) {
611                     newcp.constant_pool_tags[j] = CONSTANT_Double;
612                     ++j;
613                 } else if (o instanceof jq_Type) {
614                     newcp.constant_pool_tags[j] = CONSTANT_ResolvedClass;
615                 } else if (o instanceof String) {
616                     newcp.constant_pool_tags[j] = CONSTANT_String;
617                 } else if (o instanceof jq_NameAndDesc) {
618                     newcp.constant_pool_tags[j] = CONSTANT_NameAndType;
619                 } else if (o instanceof jq_InstanceMethod) {
620                     newcp.constant_pool_tags[j] = CONSTANT_ResolvedIMethodRef;
621                 } else if (o instanceof jq_StaticMethod) {
622                     newcp.constant_pool_tags[j] = CONSTANT_ResolvedSMethodRef;
623                 } else if (o instanceof jq_InstanceField) {
624                     newcp.constant_pool_tags[j] = CONSTANT_ResolvedIFieldRef;
625                 } else if (o instanceof jq_StaticField) {
626                     newcp.constant_pool_tags[j] = CONSTANT_ResolvedSFieldRef;
627                 } else {
628                     Assert.UNREACHABLE("CP Entry "+j+": "+o);
629                 }
630             }
631             return newcp;
632         }
633 
634         public void addCode(jq_Method m) {
635             if (TRACE) Debug.writeln("Adding code for "+m);
636             byte[] bc = m.getBytecode();
637             if (bc == null) return;
638             Bytecodes.InstructionList il = new Bytecodes.InstructionList(m.getDeclaringClass().getCP(), bc);
639             this.addCode(il);
640         }
641 
642         public void addCode(Bytecodes.InstructionList il) {
643             if (TRACE) Debug.writeln("Adding code for "+il);
644             RebuildCPVisitor v = new RebuildCPVisitor();
645             il.accept(v);
646         }
647         
648         public void addExceptions(jq_Method m) {
649             byte[] bc = m.getBytecode();
650             if (bc == null) return;
651             jq_TryCatchBC[] t = m.getExceptionTable();
652             for (int i=0; i<t.length; ++i) {
653                 jq_Class type = t[i].getExceptionType();
654                 if (type != null)
655                     addType(type);
656             }
657         }
658 
659         public void addAttributeNames(jq_Member f) {
660             if (TRACE) Debug.writeln("Adding attribute names for "+f);
661             Map m = f.getAttributes();
662             for (Iterator i = m.entrySet().iterator(); i.hasNext(); ) {
663                 Map.Entry e = (Map.Entry)i.next();
664                 Assert._assert(e.getKey() instanceof Utf8);
665                 new_entries.put(e.getKey(), null);
666             }
667         }
668         
669         public void dump(DataOutput out) throws IOException {
670             // note: this relies on the fact that the two iterators return the same order
671             int cp_size = renumber();
672             int j = 0;
673             Assert._assert(cp_size <= Character.MAX_VALUE);
674             out.writeChar(cp_size);
675             Set entrySet = new_entries.entrySet();
676             Iterator i = entrySet.iterator();
677             while (i.hasNext()) {
678                 Map.Entry e = (Map.Entry)i.next();
679                 Object o = e.getKey();
680                 char index = ((Character)e.getValue()).charValue();
681                 ++j; Assert._assert(index == j);
682                 if (o instanceof Utf8) {
683                     out.writeByte(CONSTANT_Utf8);
684                     ((Utf8)o).dump(out);
685                 } else if (o instanceof Integer) {
686                     out.writeByte(CONSTANT_Integer);
687                     out.writeInt(((Integer)o).intValue());
688                 } else if (o instanceof Float) {
689                     out.writeByte(CONSTANT_Float);
690                     out.writeFloat(((Float)o).floatValue());
691                 } else if (o instanceof Long) {
692                     out.writeByte(CONSTANT_Long);
693                     out.writeLong(((Long)o).longValue());
694                     ++j;
695                 } else if (o instanceof Double) {
696                     out.writeByte(CONSTANT_Double);
697                     out.writeDouble(((Double)o).doubleValue());
698                     ++j;
699                 } else if (o instanceof jq_Type) {
700                     out.writeByte(CONSTANT_Class);
701                     Utf8 u = ((jq_Type)o).getDesc();
702                     if (o instanceof jq_Class)
703                         u = u.getClassName();
704                     out.writeChar(get(u));
705                 } else if (o instanceof String) {
706                     out.writeByte(CONSTANT_String);
707                     out.writeChar(get(Utf8.get((String)o)));
708                 } else if (o instanceof jq_NameAndDesc) {
709                     out.writeByte(CONSTANT_NameAndType);
710                     jq_NameAndDesc f = (jq_NameAndDesc)o;
711                     out.writeChar(get(f.getName()));
712                     out.writeChar(get(f.getDesc()));
713                 } else if (o instanceof jq_Member) {
714                     byte b = CONSTANT_MethodRef;
715                     jq_Member f = (jq_Member)o;
716                     if (f instanceof jq_Field) {
717                         b = CONSTANT_FieldRef;
718                     } else if (f instanceof jq_InstanceMethod) {
719                         f.getDeclaringClass().load();
720                         if (f.getDeclaringClass().isInterface()) {
721                             b = CONSTANT_InterfaceMethodRef;
722                         }
723                     }
724                     out.writeByte(b);
725                     out.writeChar(get(f.getDeclaringClass()));
726                     out.writeChar(get(f.getNameAndDesc()));
727                 } else {
728                     Assert.UNREACHABLE();
729                 }
730             }
731         }
732 
733         public char get(Object o) {
734             Assert._assert(o != null);
735             if (o instanceof Class) o = Reflection.getJQType((Class)o);
736             Character c = (Character)new_entries.get(o);
737             if (c == null) {
738                 Assert.UNREACHABLE("No such constant pool entry: type "+o.getClass()+" value "+o);
739             }
740             return c.charValue();
741         }
742 
743         public void addString(String o) {
744             if (TRACE) Debug.writeln("Adding string "+o);
745             new_entries.put(Utf8.get(o), null);
746             new_entries.put(o, null);
747         }
748         public void addType(jq_Type o) {
749             if (TRACE) Debug.writeln("Adding type "+o);
750             Utf8 u = o.getDesc();
751             if (o instanceof jq_Class)
752                 u = u.getClassName();
753             new_entries.put(u, null);
754             new_entries.put(o, null);
755         }
756         public void addMember(jq_Member o) {
757             if (TRACE) Debug.writeln("Adding member "+o);
758             new_entries.put(o.getName(), null);
759             new_entries.put(o.getDesc(), null);
760             new_entries.put(o.getNameAndDesc(), null);
761             addType(o.getDeclaringClass());
762             new_entries.put(o, null);
763         }
764         public void addUtf8(Utf8 o) {
765             if (TRACE) Debug.writeln("Adding Utf8 "+o);
766             new_entries.put(o, null);
767         }
768         public void addOther(Object o) {
769             Assert._assert(!(o instanceof String));
770             Assert._assert(!(o instanceof Class));
771             if (o == null) return;
772             if (TRACE) Debug.writeln("Adding other ("+o.getClass().getName()+") "+o);
773             new_entries.put(o, null);
774         }
775         public void remove(Object o) {
776             if (TRACE) Debug.writeln("Removing "+o);
777             new_entries.remove(o);
778         }
779         
780         public void resetIndices(Bytecodes.InstructionList il) {
781             if (TRACE) Debug.writeln("Resetting indices of "+il);
782             final jq_ConstantPool.ConstantPoolRebuilder my_cpr = this;
783             Bytecodes.EmptyVisitor v = new Bytecodes.EmptyVisitor() {
784                 public void visitCPInstruction(Bytecodes.CPInstruction i) {
785                     i.setIndex(my_cpr);
786                     Assert._assert(i.getIndex() != 0);
787                 }
788             };
789             il.accept(v);
790         }
791         
792         class RebuildCPVisitor extends Bytecodes.EmptyVisitor {
793             public void visitCPInstruction(Bytecodes.CPInstruction i) {
794                 Object o = i.getObject();
795                 if (o instanceof String) {
796                     addString((String)o);
797                 } else if (o instanceof Utf8) {
798                     addUtf8((Utf8)o);
799                 } else if (o instanceof jq_Type) {
800                     addType((jq_Type)o);
801                 } else if (o instanceof jq_Member) {
802                     addMember((jq_Member)o);
803                 } else if (o instanceof Class) {
804                     addType(Reflection.getJQType((Class)o));
805                 } else {
806                     addOther(o);
807                 }
808             }
809         }
810     }
811     
812     /***
813      * As opposed to <code>ConstantPoolRebuilder<\code>, this class
814      * does not COMPLETELY rebuild the constant pool. It does instead add new entries
815      * to the constantpool given as arguments to its constructor
816      * @author Chrislain Razafimahefa <razafima@cui.unige.ch>
817      */
818     public static class ConstantPoolAdder extends ConstantPoolRebuilder {
819         jq_ConstantPool cp;
820 
821         public ConstantPoolAdder(jq_ConstantPool cp) {
822             this.cp = cp;
823         }
824 
825         public jq_ConstantPool finish() {
826             // use this cp adder to add entrys.
827             Adder adder = cp.getAdder();
828             int index = -1;
829 
830             //int index = cp.length; // index where to start for adding
831             //jq.assert(index <= Character.MAX_VALUE);
832             //jq_ConstantPool newcp = new jq_ConstantPool(cp_size);
833             Set entrySet = new_entries.entrySet();
834             Iterator i = entrySet.iterator();
835             while (i.hasNext()) {
836                 Map.Entry e = (Map.Entry) i.next();
837                 Object o = e.getKey();
838 
839                 //char index = ((Character)e.getValue()).charValue();
840                 //++j; jq.assert(index == j, (int)index + "!=" + (int)j);
841                 //System.out.println("CP Entry "+j+": "+o);
842                 //newcp.constant_pool[j] = o;
843 
844                 if (o instanceof Utf8) {
845                     index = adder.add(o, CONSTANT_Utf8);
846                     //newcp.constant_pool_tags[j] = CONSTANT_Utf8;
847                 } else if (o instanceof Integer) {
848                     index = adder.add(o, CONSTANT_Integer);
849                     //newcp.constant_pool_tags[j] = CONSTANT_Integer;
850                 } else if (o instanceof Float) {
851                     index = adder.add(o, CONSTANT_Float);
852                     //newcp.constant_pool_tags[j] = CONSTANT_Float;
853                 } else if (o instanceof Long) {
854                     index = adder.add(o, CONSTANT_Long);
855                     //newcp.constant_pool_tags[j] = CONSTANT_Long;
856                     //++j;
857                 } else if (o instanceof Double) {
858                     index = adder.add(o, CONSTANT_Double);
859                     //newcp.constant_pool_tags[j] = CONSTANT_Double;
860                     //++j;
861                 } else if (o instanceof jq_Type) {
862                     index = adder.add(o, CONSTANT_ResolvedClass);
863                     //newcp.constant_pool_tags[j] = CONSTANT_ResolvedClass;
864                 } else if (o instanceof String) {
865                     index = adder.add(o, CONSTANT_String);
866                     //newcp.constant_pool_tags[j] = CONSTANT_String;
867                 } else if (o instanceof jq_NameAndDesc) {
868                     index = adder.add(o, CONSTANT_NameAndType);
869                     //newcp.constant_pool_tags[j] = CONSTANT_NameAndType;
870                 } else if (o instanceof jq_InstanceMethod) {
871                     index = adder.add(o, CONSTANT_ResolvedIMethodRef);
872                     //newcp.constant_pool_tags[j] = CONSTANT_ResolvedIMethodRef;
873                 } else if (o instanceof jq_StaticMethod) {
874                     index = adder.add(o, CONSTANT_ResolvedSMethodRef);
875                     //newcp.constant_pool_tags[j] = CONSTANT_ResolvedSMethodRef;
876                 } else if (o instanceof jq_InstanceField) {
877                     index = adder.add(o, CONSTANT_ResolvedIFieldRef);
878                     //newcp.constant_pool_tags[j] = CONSTANT_ResolvedIFieldRef;
879                 } else if (o instanceof jq_StaticField) {
880                     index = adder.add(o, CONSTANT_ResolvedSFieldRef);
881                     //newcp.constant_pool_tags[j] = CONSTANT_ResolvedSFieldRef;
882                 } else {
883                     Assert.UNREACHABLE();
884                 }
885 
886                 e.setValue(new Character((char) (index++)));
887             }
888 
889             adder.finish();
890             return cp;
891         }
892 
893         public char get(Object o) {
894             if (o instanceof Class) o = Reflection.getJQType((Class)o);
895             Character c = (Character) new_entries.get(o);
896             if (c == null) {
897                 new_entries.put(o, null);
898                 finish();
899                 c = (Character) new_entries.get(o);
900             }
901             return c.charValue();
902         }
903 
904         public void remove(Object o) {
905             Assert.UNREACHABLE(
906                 "No remove allowed in jq_ConstantPool.ConstantPoolAdder! ");
907         }
908 
909         public void dump(DataOutput out) throws IOException {
910             Assert.UNREACHABLE(
911                 "TODO: implement Dump in jq_ConstantPool.ConstantPoolAdder! ");
912         }
913 
914     }
915 }