1
2
3
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
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
46 int constant_pool_count = constant_pool.length;
47 for (int i=1; i<constant_pool_count; ++i) {
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
69 constant_pool[i] = new Character((char)in.readUnsignedShort());
70 break;
71 case CONSTANT_NameAndType:
72 case CONSTANT_FieldRef:
73 case CONSTANT_MethodRef:
74 case CONSTANT_InterfaceMethodRef: {
75
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);
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
95 int constant_pool_count = constant_pool.length;
96 for (int i=1; i<constant_pool_count; ++i) {
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
106 break;
107 case CONSTANT_NameAndType:
108
109 break;
110 case CONSTANT_Class:
111 resolveClass(cl, i);
112 break;
113 case CONSTANT_ResolvedClass:
114
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
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
137 resolveClass(cl, class_index);
138 }
139 } else {
140
141 }
142
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
169 if (clazz.isLoaded()) {
170 jq_Member mem = clazz.getDeclaredMember(nd);
171 if (mem == null) {
172
173 if (TRACE) Debug.writeln("No such member: "+clazz+"."+nd+", referenced by cp idx "+(int)i);
174 if (false) {
175
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
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
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
307
308
309
310
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
341
342
343
344
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
375
376
377
378
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
410
411
412
413
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
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
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
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
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
827 Adder adder = cp.getAdder();
828 int index = -1;
829
830
831
832
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
840
841
842
843
844 if (o instanceof Utf8) {
845 index = adder.add(o, CONSTANT_Utf8);
846
847 } else if (o instanceof Integer) {
848 index = adder.add(o, CONSTANT_Integer);
849
850 } else if (o instanceof Float) {
851 index = adder.add(o, CONSTANT_Float);
852
853 } else if (o instanceof Long) {
854 index = adder.add(o, CONSTANT_Long);
855
856
857 } else if (o instanceof Double) {
858 index = adder.add(o, CONSTANT_Double);
859
860
861 } else if (o instanceof jq_Type) {
862 index = adder.add(o, CONSTANT_ResolvedClass);
863
864 } else if (o instanceof String) {
865 index = adder.add(o, CONSTANT_String);
866
867 } else if (o instanceof jq_NameAndDesc) {
868 index = adder.add(o, CONSTANT_NameAndType);
869
870 } else if (o instanceof jq_InstanceMethod) {
871 index = adder.add(o, CONSTANT_ResolvedIMethodRef);
872
873 } else if (o instanceof jq_StaticMethod) {
874 index = adder.add(o, CONSTANT_ResolvedSMethodRef);
875
876 } else if (o instanceof jq_InstanceField) {
877 index = adder.add(o, CONSTANT_ResolvedIFieldRef);
878
879 } else if (o instanceof jq_StaticField) {
880 index = adder.add(o, CONSTANT_ResolvedSFieldRef);
881
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 }