1 package serp.bytecode.lowlevel;
2
3 import java.io.*;
4 import java.util.*;
5
6 import serp.bytecode.visitor.*;
7 import serp.util.*;
8
9
10
11
12
13
14
15
16
17
18 public class ConstantPool implements VisitAcceptor {
19 private List _entries = new ArrayList(50);
20 private Map _lookup = new HashMap(50);
21
22
23
24
25 public ConstantPool() {
26 }
27
28
29
30
31 public Entry[] getEntries() {
32 List entries = new ArrayList(_entries.size());
33 Entry entry;
34 for (Iterator itr = _entries.iterator(); itr.hasNext();) {
35 entry = (Entry) itr.next();
36 if (entry != null)
37 entries.add(entry);
38 }
39 return (Entry[]) entries.toArray(new Entry[entries.size()]);
40 }
41
42
43
44
45
46
47
48
49 public Entry getEntry(int index) {
50 Entry entry = (Entry) _entries.get(index - 1);
51 if (entry == null)
52 throw new IndexOutOfBoundsException("index = " + index);
53 return entry;
54 }
55
56
57
58
59 public int indexOf(Entry entry) {
60 if (entry == null || entry.getPool() != this)
61 return 0;
62 return entry.getIndex();
63 }
64
65
66
67
68
69
70 public int addEntry(Entry entry) {
71 if (entry.getPool() != this)
72 addEntry(getKey(entry), entry);
73 return entry.getIndex();
74 }
75
76
77
78
79 private int addEntry(Object key, Entry entry) {
80 entry.setPool(this);
81 _entries.add(entry);
82 entry.setIndex(_entries.size());
83 _lookup.put(key, entry);
84 if (entry.isWide())
85 _entries.add(null);
86 return entry.getIndex();
87 }
88
89
90
91
92
93
94 public boolean removeEntry(Entry entry) {
95 if (entry == null || entry.getPool() != this)
96 return false;
97
98 int index = entry.getIndex() - 1;
99 entry.setPool(null);
100 entry.setIndex(0);
101 _entries.remove(index);
102 if (entry.isWide())
103 _entries.remove(index);
104 _lookup.remove(getKey(entry));
105
106
107 Object key;
108 for (int i = index; i < _entries.size(); i++) {
109 entry = (Entry) _entries.get(i);
110 if (entry != null) {
111 key = getKey(entry);
112 _lookup.remove(key);
113 entry.setIndex(i + 1);
114 _lookup.put(key, entry);
115 }
116 }
117 return true;
118 }
119
120
121
122
123 public void clear() {
124 Entry entry;
125 for (Iterator itr = _entries.iterator(); itr.hasNext();) {
126 entry = (Entry) itr.next();
127 if (entry != null) {
128 entry.setPool(null);
129 entry.setIndex(0);
130 }
131 }
132 _entries.clear();
133 _lookup.clear();
134 }
135
136
137
138
139
140 public int size() {
141 return _entries.size();
142 }
143
144
145
146
147
148
149
150
151 public int findUTF8Entry(String value, boolean add) {
152 if (value == null) {
153 if (add)
154 throw new NullPointerException("value = null");
155 return 0;
156 }
157
158 int index = find(value);
159 if (!add || index > 0)
160 return index;
161 return addEntry(value, new UTF8Entry(value));
162 }
163
164
165
166
167
168
169
170
171
172 public int findDoubleEntry(double value, boolean add) {
173 Double key = new Double(value);
174 int index = find(key);
175 if (!add || (index > 0))
176 return index;
177 return addEntry(key, new DoubleEntry(value));
178 }
179
180
181
182
183
184
185
186
187
188 public int findFloatEntry(float value, boolean add) {
189 Float key = new Float(value);
190 int index = find(key);
191 if (!add || index > 0)
192 return index;
193 return addEntry(key, new FloatEntry(value));
194 }
195
196
197
198
199
200
201
202
203
204 public int findIntEntry(int value, boolean add) {
205 Integer key = Numbers.valueOf(value);
206 int index = find(key);
207 if (!add || index > 0)
208 return index;
209 return addEntry(key, new IntEntry(value));
210 }
211
212
213
214
215
216
217
218
219
220 public int findLongEntry(long value, boolean add) {
221 Long key = Numbers.valueOf(value);
222 int index = find(key);
223 if (!add || index > 0)
224 return index;
225 return addEntry(key, new LongEntry(value));
226 }
227
228
229
230
231
232
233
234
235
236 public int findStringEntry(String value, boolean add) {
237 int valueIndex = findUTF8Entry(value, add);
238 if (valueIndex == 0)
239 return 0;
240
241 StringKey key = new StringKey(valueIndex);
242 int index = find(key);
243 if (!add || index > 0)
244 return index;
245 return addEntry(key, new StringEntry(valueIndex));
246 }
247
248
249
250
251
252
253
254
255
256 public int findClassEntry(String name, boolean add) {
257 int nameIndex = findUTF8Entry(name, add);
258 if (nameIndex == 0)
259 return 0;
260
261 ClassKey key = new ClassKey(nameIndex);
262 int index = find(key);
263 if (!add || index > 0)
264 return index;
265 return addEntry(key, new ClassEntry(nameIndex));
266 }
267
268
269
270
271
272
273
274
275
276
277 public int findNameAndTypeEntry(String name, String desc, boolean add) {
278 int nameIndex = findUTF8Entry(name, add);
279 if (nameIndex == 0)
280 return 0;
281 int descIndex = findUTF8Entry(desc, add);
282 if (descIndex == 0)
283 return 0;
284
285 NameAndTypeKey key = new NameAndTypeKey(nameIndex, descIndex);
286 int index = find(key);
287 if (!add || index > 0)
288 return index;
289 return addEntry(key, new NameAndTypeEntry(nameIndex, descIndex));
290 }
291
292
293
294
295
296
297
298
299
300
301
302 public int findFieldEntry(String owner, String name, String desc,
303 boolean add) {
304 return findComplexEntry(owner, name, desc, Entry.FIELD, add);
305 }
306
307
308
309
310
311
312
313
314
315
316
317 public int findMethodEntry(String owner, String name, String desc,
318 boolean add) {
319 return findComplexEntry(owner, name, desc, Entry.METHOD, add);
320 }
321
322
323
324
325
326
327
328
329
330
331
332 public int findInterfaceMethodEntry(String owner, String name, String desc,
333 boolean add) {
334 return findComplexEntry(owner, name, desc, Entry.INTERFACEMETHOD, add);
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348 private int findComplexEntry(String owner, String name, String desc,
349 int type, boolean add) {
350 int classIndex = findClassEntry(owner, add);
351 if (classIndex == 0)
352 return 0;
353 int descIndex = findNameAndTypeEntry(name, desc, add);
354 if (descIndex == 0)
355 return 0;
356
357 Object key = null;
358 switch (type) {
359 case Entry.FIELD:
360 key = new FieldKey(classIndex, descIndex);
361 break;
362 case Entry.METHOD:
363 key = new MethodKey(classIndex, descIndex);
364 break;
365 case Entry.INTERFACEMETHOD:
366 key = new InterfaceMethodKey(classIndex, descIndex);
367 break;
368 }
369 int index = find(key);
370 if (!add || index > 0)
371 return index;
372
373 Entry entry = null;
374 switch (type) {
375 case Entry.FIELD:
376 entry = new FieldEntry(classIndex, descIndex);
377 break;
378 case Entry.METHOD:
379 entry = new MethodEntry(classIndex, descIndex);
380 break;
381 case Entry.INTERFACEMETHOD:
382 entry = new InterfaceMethodEntry(classIndex, descIndex);
383 break;
384 }
385 return addEntry(key, entry);
386 }
387
388 public void acceptVisit(BCVisitor visit) {
389 visit.enterConstantPool(this);
390
391 Entry entry;
392 for (Iterator itr = _entries.iterator(); itr.hasNext();) {
393 entry = (Entry) itr.next();
394 if (entry == null)
395 continue;
396 visit.enterEntry(entry);
397 entry.acceptVisit(visit);
398 visit.exitEntry(entry);
399 }
400 visit.exitConstantPool(this);
401 }
402
403
404
405
406 public void read(DataInput in) throws IOException {
407 clear();
408
409 int entryCount = in.readUnsignedShort();
410 Entry entry;
411 for (int i = 1; i < entryCount; i++) {
412 entry = Entry.read(in);
413 addEntry(entry);
414 if (entry.isWide())
415 i++;
416 }
417 }
418
419
420
421
422 public void write(DataOutput out) throws IOException {
423 out.writeShort(_entries.size() + 1);
424
425 Entry entry;
426 for (Iterator itr = _entries.iterator(); itr.hasNext();) {
427 entry = (Entry) itr.next();
428 if (entry != null)
429 Entry.write(entry, out);
430 }
431 }
432
433
434
435
436 void modifyEntry(Object origKey, Entry entry) {
437 _lookup.remove(origKey);
438 _lookup.put(getKey(entry), entry);
439 }
440
441
442
443
444 private int find(Object key) {
445 Entry entry = (Entry) _lookup.get(key);
446 if (entry == null)
447 return 0;
448 return entry.getIndex();
449 }
450
451
452
453
454 static Object getKey(Entry entry) {
455 switch (entry.getType()) {
456 case Entry.CLASS:
457 return new ClassKey(((ClassEntry) entry).getNameIndex());
458 case Entry.FIELD:
459 FieldEntry fe = (FieldEntry) entry;
460 return new FieldKey(fe.getClassIndex(), fe.getNameAndTypeIndex());
461 case Entry.METHOD:
462 MethodEntry me = (MethodEntry) entry;
463 return new MethodKey(me.getClassIndex(), me.getNameAndTypeIndex());
464 case Entry.INTERFACEMETHOD:
465 InterfaceMethodEntry ime = (InterfaceMethodEntry) entry;
466 return new InterfaceMethodKey(ime.getClassIndex(),
467 ime.getNameAndTypeIndex());
468 case Entry.STRING:
469 return new StringKey(((StringEntry) entry).getStringIndex());
470 case Entry.INT:
471 case Entry.FLOAT:
472 case Entry.LONG:
473 case Entry.DOUBLE:
474 case Entry.UTF8:
475 return ((ConstantEntry) entry).getConstant();
476 case Entry.NAMEANDTYPE:
477 NameAndTypeEntry nte = (NameAndTypeEntry) entry;
478 return new NameAndTypeKey(nte.getNameIndex(),
479 nte.getDescriptorIndex());
480 default:
481 return null;
482 }
483 }
484
485
486
487
488 private static abstract class PtrKey {
489 private final int _index;
490
491 public PtrKey(int index) {
492 _index = index;
493 }
494
495 public int hashCode() {
496 return _index;
497 }
498
499 public boolean equals(Object other) {
500 if (other == this)
501 return true;
502 if (other.getClass() != getClass())
503 return false;
504 return ((PtrKey) other)._index == _index;
505 }
506 }
507
508
509
510
511 private static class StringKey extends PtrKey {
512 public StringKey(int index) {
513 super(index);
514 }
515 }
516
517
518
519
520 private static class ClassKey extends PtrKey {
521 public ClassKey(int index) {
522 super(index);
523 }
524 }
525
526
527
528
529 private static abstract class DoublePtrKey {
530 private final int _index1;
531 private final int _index2;
532
533 public DoublePtrKey(int index1, int index2) {
534 _index1 = index1;
535 _index2 = index2;
536 }
537
538 public int hashCode() {
539 return _index1 ^ _index2;
540 }
541
542 public boolean equals(Object other) {
543 if (other == this)
544 return true;
545 if (other.getClass() != getClass())
546 return false;
547 DoublePtrKey key = (DoublePtrKey) other;
548 return key._index1 == _index1 && key._index2 == _index2;
549 }
550 }
551
552
553
554
555 private static class NameAndTypeKey extends DoublePtrKey {
556 public NameAndTypeKey(int index1, int index2) {
557 super(index1, index2);
558 }
559 }
560
561
562
563
564 private static class FieldKey extends DoublePtrKey {
565 public FieldKey(int index1, int index2) {
566 super(index1, index2);
567 }
568 }
569
570
571
572
573 private static class MethodKey extends DoublePtrKey {
574 public MethodKey(int index1, int index2) {
575 super(index1, index2);
576 }
577 }
578
579
580
581
582 private static class InterfaceMethodKey extends DoublePtrKey {
583 public InterfaceMethodKey(int index1, int index2) {
584 super(index1, index2);
585 }
586 }
587 }