blob: 6ace172a6dd2736e74801ece414ad211fff5b03c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.java.util.jar.pack;
27
28import java.io.*;
29import java.util.*;
30
31/**
32 * Representation of constant pool entries and indexes.
33 * @author John Rose
34 */
35abstract
36class ConstantPool implements Constants {
37 private ConstantPool() {} // do not instantiate
38
39 static int verbose() {
40 return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE);
41 }
42
43 // Uniquification tables for factory methods:
44 private static final HashMap utf8Entries = new HashMap();
45 private static final HashMap classEntries = new HashMap();
46 private static final HashMap literalEntries = new HashMap();
47 private static final HashMap signatureEntries = new HashMap();
48 private static final HashMap descriptorEntries = new HashMap();
49 private static final HashMap memberEntries = new HashMap();
50
51 /** Factory for Utf8 string constants.
52 * Used for well-known strings like "SourceFile", "<init>", etc.
53 * Also used to back up more complex constant pool entries, like Class.
54 */
55 public static synchronized Utf8Entry getUtf8Entry(String value) {
56 Utf8Entry e = (Utf8Entry) utf8Entries.get(value);
57 if (e == null) {
58 e = new Utf8Entry(value);
59 utf8Entries.put(e.stringValue(), e);
60 }
61 return e;
62 }
63 /** Factory for Class constants. */
64 public static synchronized ClassEntry getClassEntry(String name) {
65 ClassEntry e = (ClassEntry) classEntries.get(name);
66 if (e == null) {
67 e = (ClassEntry) new ClassEntry(getUtf8Entry(name));
68 assert(name.equals(e.stringValue()));
69 classEntries.put(e.stringValue(), e);
70 }
71 return e;
72 }
73 /** Factory for literal constants (String, Integer, etc.). */
74 public static synchronized LiteralEntry getLiteralEntry(Comparable value) {
75 LiteralEntry e = (LiteralEntry) literalEntries.get(value);
76 if (e == null) {
77 if (value instanceof String)
78 e = new StringEntry(getUtf8Entry((String)value));
79 else
80 e = new NumberEntry((Number)value);
81 literalEntries.put(value, e);
82 }
83 return e;
84 }
85 /** Factory for literal constants (String, Integer, etc.). */
86 public static synchronized StringEntry getStringEntry(String value) {
87 return (StringEntry) getLiteralEntry(value);
88 }
89
90 /** Factory for signature (type) constants. */
91 public static synchronized SignatureEntry getSignatureEntry(String type) {
92 SignatureEntry e = (SignatureEntry) signatureEntries.get(type);
93 if (e == null) {
94 e = new SignatureEntry(type);
95 assert(e.stringValue().equals(type));
96 signatureEntries.put(type, e);
97 }
98 return e;
99 }
100 // Convenience overloading.
101 public static SignatureEntry getSignatureEntry(Utf8Entry formRef, ClassEntry[] classRefs) {
102 return getSignatureEntry(SignatureEntry.stringValueOf(formRef, classRefs));
103 }
104
105 /** Factory for descriptor (name-and-type) constants. */
106 public static synchronized DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) {
107 String key = DescriptorEntry.stringValueOf(nameRef, typeRef);
108 DescriptorEntry e = (DescriptorEntry) descriptorEntries.get(key);
109 if (e == null) {
110 e = new DescriptorEntry(nameRef, typeRef);
111 assert(e.stringValue().equals(key))
112 : (e.stringValue()+" != "+(key));
113 descriptorEntries.put(key, e);
114 }
115 return e;
116 }
117 // Convenience overloading.
118 public static DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, Utf8Entry typeRef) {
119 return getDescriptorEntry(nameRef, getSignatureEntry(typeRef.stringValue()));
120 }
121
122 /** Factory for member reference constants. */
123 public static synchronized MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) {
124 String key = MemberEntry.stringValueOf(tag, classRef, descRef);
125 MemberEntry e = (MemberEntry) memberEntries.get(key);
126 if (e == null) {
127 e = new MemberEntry(tag, classRef, descRef);
128 assert(e.stringValue().equals(key))
129 : (e.stringValue()+" != "+(key));
130 memberEntries.put(key, e);
131 }
132 return e;
133 }
134
135
136 /** Entries in the constant pool. */
137 public static abstract
138 class Entry implements Comparable {
139 protected final byte tag; // a CONSTANT_foo code
140 protected int valueHash; // cached hashCode
141
142 protected Entry(byte tag) {
143 this.tag = tag;
144 }
145
146 public final byte getTag() {
147 return tag;
148 }
149
150 public Entry getRef(int i) {
151 return null;
152 }
153
154 public boolean sameTagAs(Object o) {
155 return (o instanceof Entry) && ((Entry)o).tag == tag;
156 }
157 public boolean eq(Entry that) { // same reference
158 assert(that != null);
159 return this == that || this.equals(that);
160 }
161
162 // Equality of Entries is value-based.
163 public abstract boolean equals(Object o);
164 public final int hashCode() {
165 if (valueHash == 0) {
166 valueHash = computeValueHash();
167 if (valueHash == 0) valueHash = 1;
168 }
169 return valueHash;
170 }
171 protected abstract int computeValueHash();
172
173 public abstract int compareTo(Object o);
174
175 protected int superCompareTo(Object o) {
176 Entry that = (Entry) o;
177
178 if (this.tag != that.tag) {
179 return TAG_ORDER[this.tag] - TAG_ORDER[that.tag];
180 }
181
182 return 0; // subclasses must refine this
183 }
184
185 public final boolean isDoubleWord() {
186 return tag == CONSTANT_Double || tag == CONSTANT_Long;
187 }
188
189 public final boolean tagMatches(int tag) {
190 return (this.tag == tag);
191 }
192
193 public String toString() {
194 String valuePrint = stringValue();
195 if (verbose() > 4) {
196 if (valueHash != 0)
197 valuePrint += " hash="+valueHash;
198 valuePrint += " id="+System.identityHashCode(this);
199 }
200 return tagName(tag)+"="+valuePrint;
201 }
202 public abstract String stringValue();
203 }
204
205 public static
206 class Utf8Entry extends Entry {
207 final String value;
208
209 Utf8Entry(String value) {
210 super(CONSTANT_Utf8);
211 this.value = value.intern();
212 hashCode(); // force computation of valueHash
213 }
214 protected int computeValueHash() {
215 return value.hashCode();
216 }
217 public boolean equals(Object o) {
218 if (!sameTagAs(o)) return false;
219 // Use reference equality of interned strings:
220 return ((Utf8Entry)o).value == value;
221 }
222 public int compareTo(Object o) {
223 int x = superCompareTo(o);
224 if (x == 0) {
225 x = value.compareTo(((Utf8Entry)o).value);
226 }
227 return x;
228 }
229 public String stringValue() {
230 return value;
231 }
232 }
233
234 static boolean isMemberTag(byte tag) {
235 switch (tag) {
236 case CONSTANT_Fieldref:
237 case CONSTANT_Methodref:
238 case CONSTANT_InterfaceMethodref:
239 return true;
240 }
241 return false;
242 }
243
244 static byte numberTagOf(Number value) {
245 if (value instanceof Integer) return CONSTANT_Integer;
246 if (value instanceof Float) return CONSTANT_Float;
247 if (value instanceof Long) return CONSTANT_Long;
248 if (value instanceof Double) return CONSTANT_Double;
249 throw new RuntimeException("bad literal value "+value);
250 }
251
252 public static abstract
253 class LiteralEntry extends Entry {
254 protected LiteralEntry(byte tag) {
255 super(tag);
256 }
257
258 public abstract Comparable literalValue();
259 }
260
261 public static
262 class NumberEntry extends LiteralEntry {
263 final Number value;
264 NumberEntry(Number value) {
265 super(numberTagOf(value));
266 this.value = value;
267 hashCode(); // force computation of valueHash
268 }
269 protected int computeValueHash() {
270 return value.hashCode();
271 }
272
273 public boolean equals(Object o) {
274 if (!sameTagAs(o)) return false;
275 return (((NumberEntry)o).value).equals(value);
276 }
277 public int compareTo(Object o) {
278 int x = superCompareTo(o);
279 if (x == 0) {
280 x = ((Comparable)value).compareTo(((NumberEntry)o).value);
281 }
282 return x;
283 }
284 public Number numberValue() {
285 return value;
286 }
287 public Comparable literalValue() {
288 return (Comparable) value;
289 }
290 public String stringValue() {
291 return value.toString();
292 }
293 }
294
295 public static
296 class StringEntry extends LiteralEntry {
297 final Utf8Entry ref;
298 public Entry getRef(int i) { return i == 0 ? ref : null; }
299
300 StringEntry(Entry ref) {
301 super(CONSTANT_String);
302 this.ref = (Utf8Entry) ref;
303 hashCode(); // force computation of valueHash
304 }
305 protected int computeValueHash() {
306 return ref.hashCode() + tag;
307 }
308 public boolean equals(Object o) {
309 if (!sameTagAs(o)) return false;
310 return ((StringEntry)o).ref.eq(ref);
311 }
312 public int compareTo(Object o) {
313 int x = superCompareTo(o);
314 if (x == 0) {
315 x = ref.compareTo(((StringEntry)o).ref);
316 }
317 return x;
318 }
319 public Comparable literalValue() {
320 return ref.stringValue();
321 }
322 public String stringValue() {
323 return ref.stringValue();
324 }
325 }
326
327 public static
328 class ClassEntry extends Entry {
329 final Utf8Entry ref;
330 public Entry getRef(int i) { return i == 0 ? ref : null; }
331
332 protected int computeValueHash() {
333 return ref.hashCode() + tag;
334 }
335 ClassEntry(Entry ref) {
336 super(CONSTANT_Class);
337 this.ref = (Utf8Entry) ref;
338 hashCode(); // force computation of valueHash
339 }
340 public boolean equals(Object o) {
341 if (!sameTagAs(o)) return false;
342 return ((ClassEntry)o).ref.eq(ref);
343 }
344 public int compareTo(Object o) {
345 int x = superCompareTo(o);
346 if (x == 0) {
347 x = ref.compareTo(((ClassEntry)o).ref);
348 }
349 return x;
350 }
351 public String stringValue() {
352 return ref.stringValue();
353 }
354 }
355
356 public static
357 class DescriptorEntry extends Entry {
358 final Utf8Entry nameRef;
359 final SignatureEntry typeRef;
360 public Entry getRef(int i) {
361 if (i == 0) return nameRef;
362 if (i == 1) return typeRef;
363 return null;
364 }
365 DescriptorEntry(Entry nameRef, Entry typeRef) {
366 super(CONSTANT_NameandType);
367 if (typeRef instanceof Utf8Entry) {
368 typeRef = getSignatureEntry(typeRef.stringValue());
369 }
370 this.nameRef = (Utf8Entry) nameRef;
371 this.typeRef = (SignatureEntry) typeRef;
372 hashCode(); // force computation of valueHash
373 }
374 protected int computeValueHash() {
375 int hc2 = typeRef.hashCode();
376 return (nameRef.hashCode() + (hc2 << 8)) ^ hc2;
377 }
378 public boolean equals(Object o) {
379 if (!sameTagAs(o)) return false;
380 DescriptorEntry that = (DescriptorEntry)o;
381 return this.nameRef.eq(that.nameRef)
382 && this.typeRef.eq(that.typeRef);
383 }
384 public int compareTo(Object o) {
385 int x = superCompareTo(o);
386 if (x == 0) {
387 DescriptorEntry that = (DescriptorEntry)o;
388 // Primary key is typeRef, not nameRef.
389 x = this.typeRef.compareTo(that.typeRef);
390 if (x == 0)
391 x = this.nameRef.compareTo(that.nameRef);
392 }
393 return x;
394 }
395 public String stringValue() {
396 return stringValueOf(nameRef, typeRef);
397 }
398 static
399 String stringValueOf(Entry nameRef, Entry typeRef) {
400 return typeRef.stringValue()+","+nameRef.stringValue();
401 }
402
403 public String prettyString() {
404 return nameRef.stringValue()+typeRef.prettyString();
405 }
406
407 public boolean isMethod() {
408 return typeRef.isMethod();
409 }
410
411 public byte getLiteralTag() {
412 return typeRef.getLiteralTag();
413 }
414 }
415
416 public static
417 class MemberEntry extends Entry {
418 final ClassEntry classRef;
419 final DescriptorEntry descRef;
420 public Entry getRef(int i) {
421 if (i == 0) return classRef;
422 if (i == 1) return descRef;
423 return null;
424 }
425 protected int computeValueHash() {
426 int hc2 = descRef.hashCode();
427 return (classRef.hashCode() + (hc2 << 8)) ^ hc2;
428 }
429
430 MemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) {
431 super(tag);
432 assert(isMemberTag(tag));
433 this.classRef = classRef;
434 this.descRef = descRef;
435 hashCode(); // force computation of valueHash
436 }
437 public boolean equals(Object o) {
438 if (!sameTagAs(o)) return false;
439 MemberEntry that = (MemberEntry)o;
440 return this.classRef.eq(that.classRef)
441 && this.descRef.eq(that.descRef);
442 }
443 public int compareTo(Object o) {
444 int x = superCompareTo(o);
445 if (x == 0) {
446 MemberEntry that = (MemberEntry)o;
447 // Primary key is classRef.
448 x = this.classRef.compareTo(that.classRef);
449 if (x == 0)
450 x = this.descRef.compareTo(that.descRef);
451 }
452 return x;
453 }
454 public String stringValue() {
455 return stringValueOf(tag, classRef, descRef);
456 }
457 static
458 String stringValueOf(byte tag, ClassEntry classRef, DescriptorEntry descRef) {
459 assert(isMemberTag(tag));
460 String pfx;
461 switch (tag) {
462 case CONSTANT_Fieldref: pfx = "Field:"; break;
463 case CONSTANT_Methodref: pfx = "Method:"; break;
464 case CONSTANT_InterfaceMethodref: pfx = "IMethod:"; break;
465 default: pfx = tag+"???"; break;
466 }
467 return pfx+classRef.stringValue()+","+descRef.stringValue();
468 }
469
470 public boolean isMethod() {
471 return descRef.isMethod();
472 }
473 }
474
475 public static
476 class SignatureEntry extends Entry {
477 final Utf8Entry formRef;
478 final ClassEntry[] classRefs;
479 String value;
480 Utf8Entry asUtf8Entry;
481 public Entry getRef(int i) {
482 if (i == 0) return formRef;
483 return i-1 < classRefs.length ? classRefs[i-1] : null;
484 }
485 SignatureEntry(String value) {
486 super(CONSTANT_Signature);
487 value = value.intern(); // always do this
488 this.value = value;
489 String[] parts = structureSignature(value);
490 formRef = getUtf8Entry(parts[0]);
491 classRefs = new ClassEntry[parts.length-1];
492 for (int i = 1; i < parts.length; i++)
493 classRefs[i-1] = getClassEntry(parts[i]);
494 hashCode(); // force computation of valueHash
495 }
496 protected int computeValueHash() {
497 stringValue(); // force computation of value
498 return value.hashCode() + tag;
499 }
500
501 public Utf8Entry asUtf8Entry() {
502 if (asUtf8Entry == null) {
503 asUtf8Entry = getUtf8Entry(stringValue());
504 }
505 return asUtf8Entry;
506 }
507
508 public boolean equals(Object o) {
509 if (!sameTagAs(o)) return false;
510 return ((SignatureEntry)o).value == value;
511 }
512 public int compareTo(Object o) {
513 int x = superCompareTo(o);
514 if (x == 0) {
515 SignatureEntry that = (SignatureEntry)o;
516 x = compareSignatures(this.value, that.value);
517 }
518 return x;
519 }
520 public String stringValue() {
521 if (value == null) {
522 value = stringValueOf(formRef, classRefs);
523 }
524 return value;
525 }
526 static
527 String stringValueOf(Utf8Entry formRef, ClassEntry[] classRefs) {
528 String[] parts = new String[1+classRefs.length];
529 parts[0] = formRef.stringValue();
530 for (int i = 1; i < parts.length; i++)
531 parts[i] = classRefs[i-1].stringValue();
532 return flattenSignature(parts).intern();
533 }
534
535 public int computeSize(boolean countDoublesTwice) {
536 String form = formRef.stringValue();
537 int min = 0;
538 int max = 1;
539 if (isMethod()) {
540 min = 1;
541 max = form.indexOf(')');
542 }
543 int size = 0;
544 for (int i = min; i < max; i++) {
545 switch (form.charAt(i)) {
546 case 'D':
547 case 'J':
548 if (countDoublesTwice) size++;
549 break;
550 case '[':
551 // Skip rest of array info.
552 while (form.charAt(i) == '[') ++i;
553 break;
554 case ';':
555 continue;
556 default:
557 assert(0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i)));
558 break;
559 }
560 size++;
561 }
562 return size;
563 }
564 public boolean isMethod() {
565 return formRef.stringValue().charAt(0) == '(';
566 }
567 public byte getLiteralTag() {
568 switch (formRef.stringValue().charAt(0)) {
569 case 'L': return CONSTANT_String;
570 case 'I': return CONSTANT_Integer;
571 case 'J': return CONSTANT_Long;
572 case 'F': return CONSTANT_Float;
573 case 'D': return CONSTANT_Double;
574 case 'B': case 'S': case 'C': case 'Z':
575 return CONSTANT_Integer;
576 }
577 assert(false);
578 return CONSTANT_None;
579 }
580 public String prettyString() {
581 String s;
582 if (isMethod()) {
583 s = formRef.stringValue();
584 s = s.substring(0, 1+s.indexOf(')'));
585 } else {
586 s = "/" + formRef.stringValue();
587 }
588 int i;
589 while ((i = s.indexOf(';')) >= 0)
590 s = s.substring(0,i) + s.substring(i+1);
591 return s;
592 }
593 }
594
595 static int compareSignatures(String s1, String s2) {
596 return compareSignatures(s1, s2, null, null);
597 }
598 static int compareSignatures(String s1, String s2, String[] p1, String[] p2) {
599 final int S1_COMES_FIRST = -1;
600 final int S2_COMES_FIRST = +1;
601 char c1 = s1.charAt(0);
602 char c2 = s2.charAt(0);
603 // fields before methods (because there are fewer of them)
604 if (c1 != '(' && c2 == '(') return S1_COMES_FIRST;
605 if (c2 != '(' && c1 == '(') return S2_COMES_FIRST;
606 if (p1 == null) p1 = structureSignature(s1);
607 if (p2 == null) p2 = structureSignature(s2);
608 /*
609 // non-classes before classes (because there are fewer of them)
610 if (p1.length == 1 && p2.length > 1) return S1_COMES_FIRST;
611 if (p2.length == 1 && p1.length > 1) return S2_COMES_FIRST;
612 // all else being equal, use the same comparison as for Utf8 strings
613 return s1.compareTo(s2);
614 */
615 if (p1.length != p2.length) return p1.length - p2.length;
616 int length = p1.length;
617 for (int i = length; --i >= 0; ) {
618 int res = p1[i].compareTo(p2[i]);
619 if (res != 0) return res;
620 }
621 assert(s1.equals(s2));
622 return 0;
623 }
624
625 static int countClassParts(Utf8Entry formRef) {
626 int num = 0;
627 String s = formRef.stringValue();
628 for (int i = 0; i < s.length(); i++) {
629 if (s.charAt(i) == 'L') ++num;
630 }
631 return num;
632 }
633
634 static String flattenSignature(String[] parts) {
635 String form = parts[0];
636 if (parts.length == 1) return form;
637 int len = form.length();
638 for (int i = 1; i < parts.length; i++) {
639 len += parts[i].length();
640 }
641 char[] sig = new char[len];
642 int j = 0;
643 int k = 1;
644 for (int i = 0; i < form.length(); i++) {
645 char ch = form.charAt(i);
646 sig[j++] = ch;
647 if (ch == 'L') {
648 String cls = parts[k++];
649 cls.getChars(0, cls.length(), sig, j);
650 j += cls.length();
651 //sig[j++] = ';';
652 }
653 }
654 assert(j == len);
655 assert(k == parts.length);
656 return new String(sig);
657 }
658
659 static private int skipClassNameChars(String sig, int i) {
660 int len = sig.length();
661 for (; i < len; i++) {
662 char ch = sig.charAt(i);
663 if (ch <= ' ') break;
664 if (ch >= ';' && ch <= '@') break;
665 }
666 return i;
667 }
668
669 static String[] structureSignature(String sig) {
670 sig = sig.intern();
671
672 int formLen = 0;
673 int nparts = 1;
674 for (int i = 0; i < sig.length(); i++) {
675 char ch = sig.charAt(i);
676 formLen++;
677 if (ch == 'L') {
678 nparts++;
679 int i2 = skipClassNameChars(sig, i+1);
680 i = i2-1; // keep the semicolon in the form
681 int i3 = sig.indexOf('<', i+1);
682 if (i3 > 0 && i3 < i2)
683 i = i3-1;
684 }
685 }
686 char[] form = new char[formLen];
687 if (nparts == 1) {
688 String[] parts = { sig };
689 return parts;
690 }
691 String[] parts = new String[nparts];
692 int j = 0;
693 int k = 1;
694 for (int i = 0; i < sig.length(); i++) {
695 char ch = sig.charAt(i);
696 form[j++] = ch;
697 if (ch == 'L') {
698 int i2 = skipClassNameChars(sig, i+1);
699 parts[k++] = sig.substring(i+1, i2);
700 i = i2;
701 --i; // keep the semicolon in the form
702 }
703 }
704 assert(j == formLen);
705 assert(k == parts.length);
706 parts[0] = new String(form);
707 //assert(flattenSignature(parts).equals(sig));
708 return parts;
709 }
710
711 // Handy constants:
712 protected static final Entry[] noRefs = {};
713 protected static final ClassEntry[] noClassRefs = {};
714
715 /** An Index is a mapping between CP entries and small integers. */
716 public static
717 class Index extends AbstractList {
718 protected String debugName;
719 protected Entry[] cpMap;
720 protected boolean flattenSigs;
721 protected Entry[] getMap() {
722 return cpMap;
723 }
724 protected Index(String debugName) {
725 this.debugName = debugName;
726 }
727 protected Index(String debugName, Entry[] cpMap) {
728 this(debugName);
729 setMap(cpMap);
730 }
731 protected void setMap(Entry[] cpMap) {
732 clearIndex();
733 this.cpMap = cpMap;
734 }
735 protected Index(String debugName, Collection cpMapList) {
736 this(debugName);
737 setMap(cpMapList);
738 }
739 protected void setMap(Collection cpMapList) {
740 cpMap = new Entry[cpMapList.size()];
741 cpMapList.toArray(cpMap);
742 setMap(cpMap);
743 }
744 public int size() {
745 return cpMap.length;
746 }
747 public Object get(int i) {
748 return cpMap[i];
749 }
750 public Entry getEntry(int i) {
751 // same as get(), with covariant return type
752 return cpMap[i];
753 }
754
755 // Find index of e in cpMap, or return -1 if none.
756 //
757 // As a special hack, if flattenSigs, signatures are
758 // treated as equivalent entries of cpMap. This is wrong
759 // fron a Collection point of view, because contains()
760 // reports true for signatures, but the iterator()
761 // never produces them!
762 private int findIndexOf(Entry e) {
763 if (indexKey == null) initializeIndex();
764 int probe = findIndexLocation(e);
765 if (indexKey[probe] != e) {
766 if (flattenSigs && e.tag == CONSTANT_Signature) {
767 SignatureEntry se = (SignatureEntry) e;
768 return findIndexOf(se.asUtf8Entry());
769 }
770 return -1;
771 }
772 int index = indexValue[probe];
773 assert(e.equals(cpMap[index]));
774 return index;
775 }
776 public boolean contains(Entry e) {
777 return findIndexOf(e) >= 0;
778 }
779 // Find index of e in cpMap. Should not return -1.
780 public int indexOf(Entry e) {
781 int index = findIndexOf(e);
782 if (index < 0 && verbose() > 0) {
783 System.out.println("not found: "+e);
784 System.out.println(" in: "+this.dumpString());
785 Thread.dumpStack();
786 }
787 assert(index >= 0);
788 return index;
789 }
790 public boolean contains(Object e) {
791 return findIndexOf((Entry)e) >= 0;
792 }
793 public int indexOf(Object e) {
794 return findIndexOf((Entry)e);
795 }
796 public int lastIndexOf(Object e) {
797 return indexOf(e);
798 }
799
800 public boolean assertIsSorted() {
801 for (int i = 1; i < cpMap.length; i++) {
802 if (cpMap[i-1].compareTo(cpMap[i]) > 0) {
803 System.out.println("Not sorted at "+(i-1)+"/"+i+": "+this.dumpString());
804 return false;
805 }
806 }
807 return true;
808 }
809
810 // internal hash table
811 protected Entry[] indexKey;
812 protected int[] indexValue;
813 protected void clearIndex() {
814 indexKey = null;
815 indexValue = null;
816 }
817 private int findIndexLocation(Entry e) {
818 int size = indexKey.length;
819 int hash = e.hashCode();
820 int probe = hash & (size - 1);
821 int stride = ((hash >>> 8) | 1) & (size - 1);
822 for (;;) {
823 Entry e1 = indexKey[probe];
824 if (e1 == e || e1 == null)
825 return probe;
826 probe += stride;
827 if (probe >= size) probe -= size;
828 }
829 }
830 private void initializeIndex() {
831 if (verbose() > 2)
832 System.out.println("initialize Index "+debugName+" ["+size()+"]");
833 int hsize0 = (int)((cpMap.length + 10) * 1.5);
834 int hsize = 1;
835 while (hsize < hsize0) hsize <<= 1;
836 indexKey = new Entry[hsize];
837 indexValue = new int[hsize];
838 for (int i = 0; i < cpMap.length; i++) {
839 Entry e = cpMap[i];
840 if (e == null) continue;
841 int probe = findIndexLocation(e);
842 assert(indexKey[probe] == null); // e has unique index
843 indexKey[probe] = e;
844 indexValue[probe] = i;
845 }
846 }
847 public Object[] toArray(Object[] a) {
848 int sz = size();
849 if (a.length < sz) return super.toArray(a);
850 System.arraycopy(cpMap, 0, a, 0, sz);
851 if (a.length > sz) a[sz] = null;
852 return a;
853 }
854 public Object[] toArray() {
855 return toArray(new Entry[size()]);
856 }
857 public Object clone() {
858 return new Index(debugName, (Entry[]) cpMap.clone());
859 }
860 public String toString() {
861 return "Index "+debugName+" ["+size()+"]";
862 }
863 public String dumpString() {
864 String s = toString();
865 s += " {\n";
866 for (int i = 0; i < cpMap.length; i++) {
867 s += " "+i+": "+cpMap[i]+"\n";
868 }
869 s += "}";
870 return s;
871 }
872 }
873
874 // Index methods.
875
876 public static
877 Index makeIndex(String debugName, Entry[] cpMap) {
878 return new Index(debugName, cpMap);
879 }
880
881 public static
882 Index makeIndex(String debugName, Collection cpMapList) {
883 return new Index(debugName, cpMapList);
884 }
885
886 /** Sort this index (destructively) into canonical order. */
887 public static
888 void sort(Index ix) {
889 // %%% Should move this into class Index.
890 ix.clearIndex();
891 Arrays.sort(ix.cpMap);
892 if (verbose() > 2)
893 System.out.println("sorted "+ix.dumpString());
894 }
895
896 /** Return a set of indexes partitioning these entries.
897 * The keys array must of length this.size(), and marks entries.
898 * The result array is as long as one plus the largest key value.
899 * Entries with a negative key are dropped from the partition.
900 */
901 public static
902 Index[] partition(Index ix, int[] keys) {
903 // %%% Should move this into class Index.
904 ArrayList parts = new ArrayList();
905 Entry[] cpMap = ix.cpMap;
906 assert(keys.length == cpMap.length);
907 for (int i = 0; i < keys.length; i++) {
908 int key = keys[i];
909 if (key < 0) continue;
910 while (key >= parts.size()) parts.add(null);
911 ArrayList part = (ArrayList) parts.get(key);
912 if (part == null) {
913 parts.set(key, part = new ArrayList());
914 }
915 part.add(cpMap[i]);
916 }
917 Index[] indexes = new Index[parts.size()];
918 for (int key = 0; key < indexes.length; key++) {
919 ArrayList part = (ArrayList) parts.get(key);
920 if (part == null) continue;
921 indexes[key] = new Index(ix.debugName+"/part#"+key, part);
922 assert(indexes[key].indexOf(part.get(0)) == 0);
923 }
924 return indexes;
925 }
926 public static
927 Index[] partitionByTag(Index ix) {
928 // Partition by tag.
929 Entry[] cpMap = ix.cpMap;
930 int[] keys = new int[cpMap.length];
931 for (int i = 0; i < keys.length; i++) {
932 Entry e = cpMap[i];
933 keys[i] = (e == null)? -1: e.tag;
934 }
935 Index[] byTag = partition(ix, keys);
936 for (int tag = 0; tag < byTag.length; tag++) {
937 if (byTag[tag] == null) continue;
938 byTag[tag].debugName = tagName(tag);
939 }
940 if (byTag.length < CONSTANT_Limit) {
941 Index[] longer = new Index[CONSTANT_Limit];
942 System.arraycopy(byTag, 0, longer, 0, byTag.length);
943 byTag = longer;
944 }
945 return byTag;
946 }
947
948 /** Coherent group of constant pool indexes. */
949 public static
950 class IndexGroup {
951 private Index indexUntyped;
952 private Index[] indexByTag = new Index[CONSTANT_Limit];
953 private int[] untypedFirstIndexByTag;
954 private int totalSize;
955 private Index[][] indexByTagAndClass;
956
957 /** Index of all CP entries of all types, in definition order. */
958 public Index getUntypedIndex() {
959 if (indexUntyped == null) {
960 untypedIndexOf(null); // warm up untypedFirstIndexByTag
961 Entry[] cpMap = new Entry[totalSize];
962 for (int tag = 0; tag < indexByTag.length; tag++) {
963 Index ix = indexByTag[tag];
964 if (ix == null) continue;
965 int ixLen = ix.cpMap.length;
966 if (ixLen == 0) continue;
967 int fillp = untypedFirstIndexByTag[tag];
968 assert(cpMap[fillp] == null);
969 assert(cpMap[fillp+ixLen-1] == null);
970 System.arraycopy(ix.cpMap, 0, cpMap, fillp, ixLen);
971 }
972 indexUntyped = new Index("untyped", cpMap);
973 }
974 return indexUntyped;
975 }
976
977 public int untypedIndexOf(Entry e) {
978 if (untypedFirstIndexByTag == null) {
979 untypedFirstIndexByTag = new int[CONSTANT_Limit];
980 int fillp = 0;
981 for (int i = 0; i < TAGS_IN_ORDER.length; i++) {
982 byte tag = TAGS_IN_ORDER[i];
983 Index ix = indexByTag[tag];
984 if (ix == null) continue;
985 int ixLen = ix.cpMap.length;
986 untypedFirstIndexByTag[tag] = fillp;
987 fillp += ixLen;
988 }
989 totalSize = fillp;
990 }
991 if (e == null) return -1;
992 int tag = e.tag;
993 Index ix = indexByTag[tag];
994 if (ix == null) return -1;
995 int idx = ix.findIndexOf(e);
996 if (idx >= 0)
997 idx += untypedFirstIndexByTag[tag];
998 return idx;
999 }
1000
1001 public void initIndexByTag(byte tag, Index ix) {
1002 assert(indexByTag[tag] == null); // do not init twice
1003 Entry[] cpMap = ix.cpMap;
1004 for (int i = 0; i < cpMap.length; i++) {
1005 // It must be a homogeneous Entry set.
1006 assert(cpMap[i].tag == tag);
1007 }
1008 if (tag == CONSTANT_Utf8) {
1009 // Special case: First Utf8 must always be empty string.
1010 assert(cpMap.length == 0 || cpMap[0].stringValue().equals(""));
1011 }
1012 indexByTag[tag] = ix;
1013 // decache indexes derived from this one:
1014 untypedFirstIndexByTag = null;
1015 indexUntyped = null;
1016 if (indexByTagAndClass != null)
1017 indexByTagAndClass[tag] = null;
1018 }
1019
1020 /** Index of all CP entries of a given tag. */
1021 public Index getIndexByTag(byte tag) {
1022 if (tag == CONSTANT_All) {
1023 return getUntypedIndex();
1024 }
1025 Index ix = indexByTag[tag];
1026 if (ix == null) {
1027 // Make an empty one by default.
1028 ix = new Index(tagName(tag), new Entry[0]);
1029 indexByTag[tag] = ix;
1030 }
1031 return ix;
1032 }
1033
1034 /** Index of all CP entries of a given tag and class. */
1035 public Index getMemberIndex(byte tag, ClassEntry classRef) {
1036 if (indexByTagAndClass == null)
1037 indexByTagAndClass = new Index[CONSTANT_Limit][];
1038 Index allClasses = getIndexByTag(CONSTANT_Class);
1039 Index[] perClassIndexes = indexByTagAndClass[tag];
1040 if (perClassIndexes == null) {
1041 // Create the partition now.
1042 // Divide up all entries of the given tag according to their class.
1043 Index allMembers = getIndexByTag(tag);
1044 int[] whichClasses = new int[allMembers.size()];
1045 for (int i = 0; i < whichClasses.length; i++) {
1046 MemberEntry e = (MemberEntry) allMembers.get(i);
1047 int whichClass = allClasses.indexOf(e.classRef);
1048 whichClasses[i] = whichClass;
1049 }
1050 perClassIndexes = partition(allMembers, whichClasses);
1051 for (int i = 0; i < perClassIndexes.length; i++)
1052 assert(perClassIndexes[i]==null
1053 || perClassIndexes[i].assertIsSorted());
1054 indexByTagAndClass[tag] = perClassIndexes;
1055 }
1056 int whichClass = allClasses.indexOf(classRef);
1057 return perClassIndexes[whichClass];
1058 }
1059
1060 // Given the sequence of all methods of the given name and class,
1061 // produce the ordinal of this particular given overloading.
1062 public int getOverloadingIndex(MemberEntry methodRef) {
1063 Index ix = getMemberIndex(methodRef.tag, methodRef.classRef);
1064 Utf8Entry nameRef = methodRef.descRef.nameRef;
1065 int ord = 0;
1066 for (int i = 0; i < ix.cpMap.length; i++) {
1067 MemberEntry e = (MemberEntry) ix.cpMap[i];
1068 if (e.equals(methodRef))
1069 return ord;
1070 if (e.descRef.nameRef.equals(nameRef))
1071 // Found a different overloading. Increment the ordinal.
1072 ord++;
1073 }
1074 throw new RuntimeException("should not reach here");
1075 }
1076
1077 // Inverse of getOverloadingIndex
1078 public MemberEntry getOverloadingForIndex(byte tag, ClassEntry classRef, String name, int which) {
1079 assert(name == name.intern());
1080 Index ix = getMemberIndex(tag, classRef);
1081 int ord = 0;
1082 for (int i = 0; i < ix.cpMap.length; i++) {
1083 MemberEntry e = (MemberEntry) ix.cpMap[i];
1084 if (e.descRef.nameRef.stringValue() == name) {
1085 if (ord == which) return e;
1086 ord++;
1087 }
1088 }
1089 throw new RuntimeException("should not reach here");
1090 }
1091
1092 public boolean haveNumbers() {
1093 for (byte tag = CONSTANT_Integer; tag <= CONSTANT_Double; tag++) {
1094 switch (tag) {
1095 case CONSTANT_Integer:
1096 case CONSTANT_Float:
1097 case CONSTANT_Long:
1098 case CONSTANT_Double:
1099 break;
1100 default:
1101 assert(false);
1102 }
1103 if (getIndexByTag(tag).size() > 0) return true;
1104 }
1105 return false;
1106 }
1107
1108 }
1109
1110 /** Close the set cpRefs under the getRef(*) relation.
1111 * Also, if flattenSigs, replace all signatures in cpRefs
1112 * by their equivalent Utf8s.
1113 * Also, discard null from cpRefs.
1114 */
1115 public static
1116 void completeReferencesIn(Set cpRefs, boolean flattenSigs) {
1117 cpRefs.remove(null);
1118 for (ListIterator work =
1119 new ArrayList(cpRefs).listIterator(cpRefs.size());
1120 work.hasPrevious(); ) {
1121 Entry e = (Entry) work.previous();
1122 work.remove(); // pop stack
1123 assert(e != null);
1124 if (flattenSigs && e.tag == CONSTANT_Signature) {
1125 SignatureEntry se = (SignatureEntry) e;
1126 Utf8Entry ue = se.asUtf8Entry();
1127 // Totally replace e by se.
1128 cpRefs.remove(se);
1129 cpRefs.add(ue);
1130 e = ue; // do not descend into the sig
1131 }
1132 // Recursively add the refs of e to cpRefs:
1133 for (int i = 0; ; i++) {
1134 Entry re = e.getRef(i);
1135 if (re == null)
1136 break; // no more refs in e
1137 if (cpRefs.add(re)) // output the ref
1138 work.add(re); // push stack, if a new ref
1139 }
1140 }
1141 }
1142
1143 static double percent(int num, int den) {
1144 return (int)((10000.0*num)/den + 0.5) / 100.0;
1145 }
1146
1147 public static String tagName(int tag) {
1148 switch (tag) {
1149 case CONSTANT_Utf8: return "Utf8";
1150 case CONSTANT_Integer: return "Integer";
1151 case CONSTANT_Float: return "Float";
1152 case CONSTANT_Long: return "Long";
1153 case CONSTANT_Double: return "Double";
1154 case CONSTANT_Class: return "Class";
1155 case CONSTANT_String: return "String";
1156 case CONSTANT_Fieldref: return "Fieldref";
1157 case CONSTANT_Methodref: return "Methodref";
1158 case CONSTANT_InterfaceMethodref: return "InterfaceMethodref";
1159 case CONSTANT_NameandType: return "NameandType";
1160
1161 // pseudo-tags:
1162 case CONSTANT_All: return "*All";
1163 case CONSTANT_None: return "*None";
1164 case CONSTANT_Signature: return "*Signature";
1165 }
1166 return "tag#"+tag;
1167 }
1168
1169 // archive constant pool definition order
1170 static final byte TAGS_IN_ORDER[] = {
1171 CONSTANT_Utf8,
1172 CONSTANT_Integer, // cp_Int
1173 CONSTANT_Float,
1174 CONSTANT_Long,
1175 CONSTANT_Double,
1176 CONSTANT_String,
1177 CONSTANT_Class,
1178 CONSTANT_Signature,
1179 CONSTANT_NameandType, // cp_Descr
1180 CONSTANT_Fieldref, // cp_Field
1181 CONSTANT_Methodref, // cp_Method
1182 CONSTANT_InterfaceMethodref // cp_Imethod
1183 };
1184 static final byte TAG_ORDER[];
1185 static {
1186 TAG_ORDER = new byte[CONSTANT_Limit];
1187 for (int i = 0; i < TAGS_IN_ORDER.length; i++) {
1188 TAG_ORDER[TAGS_IN_ORDER[i]] = (byte)(i+1);
1189 }
1190 /*
1191 System.out.println("TAG_ORDER[] = {");
1192 for (int i = 0; i < TAG_ORDER.length; i++)
1193 System.out.println(" "+TAG_ORDER[i]+",");
1194 System.out.println("};");
1195 */
1196 }
1197}