0001: /*
0002: * Copyright 2001-2003 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package com.sun.java.util.jar.pack;
0027:
0028: import java.io.*;
0029: import java.util.*;
0030:
0031: /**
0032: * Representation of constant pool entries and indexes.
0033: * @author John Rose
0034: * @version 1.25, 05/05/07
0035: */
0036: abstract class ConstantPool implements Constants {
0037: private ConstantPool() {
0038: } // do not instantiate
0039:
0040: static int verbose() {
0041: return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE);
0042: }
0043:
0044: // Uniquification tables for factory methods:
0045: private static final HashMap utf8Entries = new HashMap();
0046: private static final HashMap classEntries = new HashMap();
0047: private static final HashMap literalEntries = new HashMap();
0048: private static final HashMap signatureEntries = new HashMap();
0049: private static final HashMap descriptorEntries = new HashMap();
0050: private static final HashMap memberEntries = new HashMap();
0051:
0052: /** Factory for Utf8 string constants.
0053: * Used for well-known strings like "SourceFile", "<init>", etc.
0054: * Also used to back up more complex constant pool entries, like Class.
0055: */
0056: public static synchronized Utf8Entry getUtf8Entry(String value) {
0057: Utf8Entry e = (Utf8Entry) utf8Entries.get(value);
0058: if (e == null) {
0059: e = new Utf8Entry(value);
0060: utf8Entries.put(e.stringValue(), e);
0061: }
0062: return e;
0063: }
0064:
0065: /** Factory for Class constants. */
0066: public static synchronized ClassEntry getClassEntry(String name) {
0067: ClassEntry e = (ClassEntry) classEntries.get(name);
0068: if (e == null) {
0069: e = (ClassEntry) new ClassEntry(getUtf8Entry(name));
0070: assert (name.equals(e.stringValue()));
0071: classEntries.put(e.stringValue(), e);
0072: }
0073: return e;
0074: }
0075:
0076: /** Factory for literal constants (String, Integer, etc.). */
0077: public static synchronized LiteralEntry getLiteralEntry(
0078: Comparable value) {
0079: LiteralEntry e = (LiteralEntry) literalEntries.get(value);
0080: if (e == null) {
0081: if (value instanceof String)
0082: e = new StringEntry(getUtf8Entry((String) value));
0083: else
0084: e = new NumberEntry((Number) value);
0085: literalEntries.put(value, e);
0086: }
0087: return e;
0088: }
0089:
0090: /** Factory for literal constants (String, Integer, etc.). */
0091: public static synchronized StringEntry getStringEntry(String value) {
0092: return (StringEntry) getLiteralEntry(value);
0093: }
0094:
0095: /** Factory for signature (type) constants. */
0096: public static synchronized SignatureEntry getSignatureEntry(
0097: String type) {
0098: SignatureEntry e = (SignatureEntry) signatureEntries.get(type);
0099: if (e == null) {
0100: e = new SignatureEntry(type);
0101: assert (e.stringValue().equals(type));
0102: signatureEntries.put(type, e);
0103: }
0104: return e;
0105: }
0106:
0107: // Convenience overloading.
0108: public static SignatureEntry getSignatureEntry(Utf8Entry formRef,
0109: ClassEntry[] classRefs) {
0110: return getSignatureEntry(SignatureEntry.stringValueOf(formRef,
0111: classRefs));
0112: }
0113:
0114: /** Factory for descriptor (name-and-type) constants. */
0115: public static synchronized DescriptorEntry getDescriptorEntry(
0116: Utf8Entry nameRef, SignatureEntry typeRef) {
0117: String key = DescriptorEntry.stringValueOf(nameRef, typeRef);
0118: DescriptorEntry e = (DescriptorEntry) descriptorEntries
0119: .get(key);
0120: if (e == null) {
0121: e = new DescriptorEntry(nameRef, typeRef);
0122: assert (e.stringValue().equals(key)) : (e.stringValue()
0123: + " != " + (key));
0124: descriptorEntries.put(key, e);
0125: }
0126: return e;
0127: }
0128:
0129: // Convenience overloading.
0130: public static DescriptorEntry getDescriptorEntry(Utf8Entry nameRef,
0131: Utf8Entry typeRef) {
0132: return getDescriptorEntry(nameRef, getSignatureEntry(typeRef
0133: .stringValue()));
0134: }
0135:
0136: /** Factory for member reference constants. */
0137: public static synchronized MemberEntry getMemberEntry(byte tag,
0138: ClassEntry classRef, DescriptorEntry descRef) {
0139: String key = MemberEntry.stringValueOf(tag, classRef, descRef);
0140: MemberEntry e = (MemberEntry) memberEntries.get(key);
0141: if (e == null) {
0142: e = new MemberEntry(tag, classRef, descRef);
0143: assert (e.stringValue().equals(key)) : (e.stringValue()
0144: + " != " + (key));
0145: memberEntries.put(key, e);
0146: }
0147: return e;
0148: }
0149:
0150: /** Entries in the constant pool. */
0151: public static abstract class Entry implements Comparable {
0152: protected final byte tag; // a CONSTANT_foo code
0153: protected int valueHash; // cached hashCode
0154:
0155: protected Entry(byte tag) {
0156: this .tag = tag;
0157: }
0158:
0159: public final byte getTag() {
0160: return tag;
0161: }
0162:
0163: public Entry getRef(int i) {
0164: return null;
0165: }
0166:
0167: public boolean sameTagAs(Object o) {
0168: return (o instanceof Entry) && ((Entry) o).tag == tag;
0169: }
0170:
0171: public boolean eq(Entry that) { // same reference
0172: assert (that != null);
0173: return this == that || this .equals(that);
0174: }
0175:
0176: // Equality of Entries is value-based.
0177: public abstract boolean equals(Object o);
0178:
0179: public final int hashCode() {
0180: if (valueHash == 0) {
0181: valueHash = computeValueHash();
0182: if (valueHash == 0)
0183: valueHash = 1;
0184: }
0185: return valueHash;
0186: }
0187:
0188: protected abstract int computeValueHash();
0189:
0190: public abstract int compareTo(Object o);
0191:
0192: protected int super CompareTo(Object o) {
0193: Entry that = (Entry) o;
0194:
0195: if (this .tag != that.tag) {
0196: return TAG_ORDER[this .tag] - TAG_ORDER[that.tag];
0197: }
0198:
0199: return 0; // subclasses must refine this
0200: }
0201:
0202: public final boolean isDoubleWord() {
0203: return tag == CONSTANT_Double || tag == CONSTANT_Long;
0204: }
0205:
0206: public final boolean tagMatches(int tag) {
0207: return (this .tag == tag);
0208: }
0209:
0210: public String toString() {
0211: String valuePrint = stringValue();
0212: if (verbose() > 4) {
0213: if (valueHash != 0)
0214: valuePrint += " hash=" + valueHash;
0215: valuePrint += " id=" + System.identityHashCode(this );
0216: }
0217: return tagName(tag) + "=" + valuePrint;
0218: }
0219:
0220: public abstract String stringValue();
0221: }
0222:
0223: public static class Utf8Entry extends Entry {
0224: final String value;
0225:
0226: Utf8Entry(String value) {
0227: super (CONSTANT_Utf8);
0228: this .value = value.intern();
0229: hashCode(); // force computation of valueHash
0230: }
0231:
0232: protected int computeValueHash() {
0233: return value.hashCode();
0234: }
0235:
0236: public boolean equals(Object o) {
0237: if (!sameTagAs(o))
0238: return false;
0239: // Use reference equality of interned strings:
0240: return ((Utf8Entry) o).value == value;
0241: }
0242:
0243: public int compareTo(Object o) {
0244: int x = super CompareTo(o);
0245: if (x == 0) {
0246: x = value.compareTo(((Utf8Entry) o).value);
0247: }
0248: return x;
0249: }
0250:
0251: public String stringValue() {
0252: return value;
0253: }
0254: }
0255:
0256: static boolean isMemberTag(byte tag) {
0257: switch (tag) {
0258: case CONSTANT_Fieldref:
0259: case CONSTANT_Methodref:
0260: case CONSTANT_InterfaceMethodref:
0261: return true;
0262: }
0263: return false;
0264: }
0265:
0266: static byte numberTagOf(Number value) {
0267: if (value instanceof Integer)
0268: return CONSTANT_Integer;
0269: if (value instanceof Float)
0270: return CONSTANT_Float;
0271: if (value instanceof Long)
0272: return CONSTANT_Long;
0273: if (value instanceof Double)
0274: return CONSTANT_Double;
0275: throw new RuntimeException("bad literal value " + value);
0276: }
0277:
0278: public static abstract class LiteralEntry extends Entry {
0279: protected LiteralEntry(byte tag) {
0280: super (tag);
0281: }
0282:
0283: public abstract Comparable literalValue();
0284: }
0285:
0286: public static class NumberEntry extends LiteralEntry {
0287: final Number value;
0288:
0289: NumberEntry(Number value) {
0290: super (numberTagOf(value));
0291: this .value = value;
0292: hashCode(); // force computation of valueHash
0293: }
0294:
0295: protected int computeValueHash() {
0296: return value.hashCode();
0297: }
0298:
0299: public boolean equals(Object o) {
0300: if (!sameTagAs(o))
0301: return false;
0302: return (((NumberEntry) o).value).equals(value);
0303: }
0304:
0305: public int compareTo(Object o) {
0306: int x = super CompareTo(o);
0307: if (x == 0) {
0308: x = ((Comparable) value)
0309: .compareTo(((NumberEntry) o).value);
0310: }
0311: return x;
0312: }
0313:
0314: public Number numberValue() {
0315: return value;
0316: }
0317:
0318: public Comparable literalValue() {
0319: return (Comparable) value;
0320: }
0321:
0322: public String stringValue() {
0323: return value.toString();
0324: }
0325: }
0326:
0327: public static class StringEntry extends LiteralEntry {
0328: final Utf8Entry ref;
0329:
0330: public Entry getRef(int i) {
0331: return i == 0 ? ref : null;
0332: }
0333:
0334: StringEntry(Entry ref) {
0335: super (CONSTANT_String);
0336: this .ref = (Utf8Entry) ref;
0337: hashCode(); // force computation of valueHash
0338: }
0339:
0340: protected int computeValueHash() {
0341: return ref.hashCode() + tag;
0342: }
0343:
0344: public boolean equals(Object o) {
0345: if (!sameTagAs(o))
0346: return false;
0347: return ((StringEntry) o).ref.eq(ref);
0348: }
0349:
0350: public int compareTo(Object o) {
0351: int x = super CompareTo(o);
0352: if (x == 0) {
0353: x = ref.compareTo(((StringEntry) o).ref);
0354: }
0355: return x;
0356: }
0357:
0358: public Comparable literalValue() {
0359: return ref.stringValue();
0360: }
0361:
0362: public String stringValue() {
0363: return ref.stringValue();
0364: }
0365: }
0366:
0367: public static class ClassEntry extends Entry {
0368: final Utf8Entry ref;
0369:
0370: public Entry getRef(int i) {
0371: return i == 0 ? ref : null;
0372: }
0373:
0374: protected int computeValueHash() {
0375: return ref.hashCode() + tag;
0376: }
0377:
0378: ClassEntry(Entry ref) {
0379: super (CONSTANT_Class);
0380: this .ref = (Utf8Entry) ref;
0381: hashCode(); // force computation of valueHash
0382: }
0383:
0384: public boolean equals(Object o) {
0385: if (!sameTagAs(o))
0386: return false;
0387: return ((ClassEntry) o).ref.eq(ref);
0388: }
0389:
0390: public int compareTo(Object o) {
0391: int x = super CompareTo(o);
0392: if (x == 0) {
0393: x = ref.compareTo(((ClassEntry) o).ref);
0394: }
0395: return x;
0396: }
0397:
0398: public String stringValue() {
0399: return ref.stringValue();
0400: }
0401: }
0402:
0403: public static class DescriptorEntry extends Entry {
0404: final Utf8Entry nameRef;
0405: final SignatureEntry typeRef;
0406:
0407: public Entry getRef(int i) {
0408: if (i == 0)
0409: return nameRef;
0410: if (i == 1)
0411: return typeRef;
0412: return null;
0413: }
0414:
0415: DescriptorEntry(Entry nameRef, Entry typeRef) {
0416: super (CONSTANT_NameandType);
0417: if (typeRef instanceof Utf8Entry) {
0418: typeRef = getSignatureEntry(typeRef.stringValue());
0419: }
0420: this .nameRef = (Utf8Entry) nameRef;
0421: this .typeRef = (SignatureEntry) typeRef;
0422: hashCode(); // force computation of valueHash
0423: }
0424:
0425: protected int computeValueHash() {
0426: int hc2 = typeRef.hashCode();
0427: return (nameRef.hashCode() + (hc2 << 8)) ^ hc2;
0428: }
0429:
0430: public boolean equals(Object o) {
0431: if (!sameTagAs(o))
0432: return false;
0433: DescriptorEntry that = (DescriptorEntry) o;
0434: return this .nameRef.eq(that.nameRef)
0435: && this .typeRef.eq(that.typeRef);
0436: }
0437:
0438: public int compareTo(Object o) {
0439: int x = super CompareTo(o);
0440: if (x == 0) {
0441: DescriptorEntry that = (DescriptorEntry) o;
0442: // Primary key is typeRef, not nameRef.
0443: x = this .typeRef.compareTo(that.typeRef);
0444: if (x == 0)
0445: x = this .nameRef.compareTo(that.nameRef);
0446: }
0447: return x;
0448: }
0449:
0450: public String stringValue() {
0451: return stringValueOf(nameRef, typeRef);
0452: }
0453:
0454: static String stringValueOf(Entry nameRef, Entry typeRef) {
0455: return typeRef.stringValue() + "," + nameRef.stringValue();
0456: }
0457:
0458: public String prettyString() {
0459: return nameRef.stringValue() + typeRef.prettyString();
0460: }
0461:
0462: public boolean isMethod() {
0463: return typeRef.isMethod();
0464: }
0465:
0466: public byte getLiteralTag() {
0467: return typeRef.getLiteralTag();
0468: }
0469: }
0470:
0471: public static class MemberEntry extends Entry {
0472: final ClassEntry classRef;
0473: final DescriptorEntry descRef;
0474:
0475: public Entry getRef(int i) {
0476: if (i == 0)
0477: return classRef;
0478: if (i == 1)
0479: return descRef;
0480: return null;
0481: }
0482:
0483: protected int computeValueHash() {
0484: int hc2 = descRef.hashCode();
0485: return (classRef.hashCode() + (hc2 << 8)) ^ hc2;
0486: }
0487:
0488: MemberEntry(byte tag, ClassEntry classRef,
0489: DescriptorEntry descRef) {
0490: super (tag);
0491: assert (isMemberTag(tag));
0492: this .classRef = classRef;
0493: this .descRef = descRef;
0494: hashCode(); // force computation of valueHash
0495: }
0496:
0497: public boolean equals(Object o) {
0498: if (!sameTagAs(o))
0499: return false;
0500: MemberEntry that = (MemberEntry) o;
0501: return this .classRef.eq(that.classRef)
0502: && this .descRef.eq(that.descRef);
0503: }
0504:
0505: public int compareTo(Object o) {
0506: int x = super CompareTo(o);
0507: if (x == 0) {
0508: MemberEntry that = (MemberEntry) o;
0509: // Primary key is classRef.
0510: x = this .classRef.compareTo(that.classRef);
0511: if (x == 0)
0512: x = this .descRef.compareTo(that.descRef);
0513: }
0514: return x;
0515: }
0516:
0517: public String stringValue() {
0518: return stringValueOf(tag, classRef, descRef);
0519: }
0520:
0521: static String stringValueOf(byte tag, ClassEntry classRef,
0522: DescriptorEntry descRef) {
0523: assert (isMemberTag(tag));
0524: String pfx;
0525: switch (tag) {
0526: case CONSTANT_Fieldref:
0527: pfx = "Field:";
0528: break;
0529: case CONSTANT_Methodref:
0530: pfx = "Method:";
0531: break;
0532: case CONSTANT_InterfaceMethodref:
0533: pfx = "IMethod:";
0534: break;
0535: default:
0536: pfx = tag + "???";
0537: break;
0538: }
0539: return pfx + classRef.stringValue() + ","
0540: + descRef.stringValue();
0541: }
0542:
0543: public boolean isMethod() {
0544: return descRef.isMethod();
0545: }
0546: }
0547:
0548: public static class SignatureEntry extends Entry {
0549: final Utf8Entry formRef;
0550: final ClassEntry[] classRefs;
0551: String value;
0552: Utf8Entry asUtf8Entry;
0553:
0554: public Entry getRef(int i) {
0555: if (i == 0)
0556: return formRef;
0557: return i - 1 < classRefs.length ? classRefs[i - 1] : null;
0558: }
0559:
0560: SignatureEntry(String value) {
0561: super (CONSTANT_Signature);
0562: value = value.intern(); // always do this
0563: this .value = value;
0564: String[] parts = structureSignature(value);
0565: formRef = getUtf8Entry(parts[0]);
0566: classRefs = new ClassEntry[parts.length - 1];
0567: for (int i = 1; i < parts.length; i++)
0568: classRefs[i - 1] = getClassEntry(parts[i]);
0569: hashCode(); // force computation of valueHash
0570: }
0571:
0572: protected int computeValueHash() {
0573: stringValue(); // force computation of value
0574: return value.hashCode() + tag;
0575: }
0576:
0577: public Utf8Entry asUtf8Entry() {
0578: if (asUtf8Entry == null) {
0579: asUtf8Entry = getUtf8Entry(stringValue());
0580: }
0581: return asUtf8Entry;
0582: }
0583:
0584: public boolean equals(Object o) {
0585: if (!sameTagAs(o))
0586: return false;
0587: return ((SignatureEntry) o).value == value;
0588: }
0589:
0590: public int compareTo(Object o) {
0591: int x = super CompareTo(o);
0592: if (x == 0) {
0593: SignatureEntry that = (SignatureEntry) o;
0594: x = compareSignatures(this .value, that.value);
0595: }
0596: return x;
0597: }
0598:
0599: public String stringValue() {
0600: if (value == null) {
0601: value = stringValueOf(formRef, classRefs);
0602: }
0603: return value;
0604: }
0605:
0606: static String stringValueOf(Utf8Entry formRef,
0607: ClassEntry[] classRefs) {
0608: String[] parts = new String[1 + classRefs.length];
0609: parts[0] = formRef.stringValue();
0610: for (int i = 1; i < parts.length; i++)
0611: parts[i] = classRefs[i - 1].stringValue();
0612: return flattenSignature(parts).intern();
0613: }
0614:
0615: public int computeSize(boolean countDoublesTwice) {
0616: String form = formRef.stringValue();
0617: int min = 0;
0618: int max = 1;
0619: if (isMethod()) {
0620: min = 1;
0621: max = form.indexOf(')');
0622: }
0623: int size = 0;
0624: for (int i = min; i < max; i++) {
0625: switch (form.charAt(i)) {
0626: case 'D':
0627: case 'J':
0628: if (countDoublesTwice)
0629: size++;
0630: break;
0631: case '[':
0632: // Skip rest of array info.
0633: while (form.charAt(i) == '[')
0634: ++i;
0635: break;
0636: case ';':
0637: continue;
0638: default:
0639: assert (0 <= JAVA_SIGNATURE_CHARS.indexOf(form
0640: .charAt(i)));
0641: break;
0642: }
0643: size++;
0644: }
0645: return size;
0646: }
0647:
0648: public boolean isMethod() {
0649: return formRef.stringValue().charAt(0) == '(';
0650: }
0651:
0652: public byte getLiteralTag() {
0653: switch (formRef.stringValue().charAt(0)) {
0654: case 'L':
0655: return CONSTANT_String;
0656: case 'I':
0657: return CONSTANT_Integer;
0658: case 'J':
0659: return CONSTANT_Long;
0660: case 'F':
0661: return CONSTANT_Float;
0662: case 'D':
0663: return CONSTANT_Double;
0664: case 'B':
0665: case 'S':
0666: case 'C':
0667: case 'Z':
0668: return CONSTANT_Integer;
0669: }
0670: assert (false);
0671: return CONSTANT_None;
0672: }
0673:
0674: public String prettyString() {
0675: String s;
0676: if (isMethod()) {
0677: s = formRef.stringValue();
0678: s = s.substring(0, 1 + s.indexOf(')'));
0679: } else {
0680: s = "/" + formRef.stringValue();
0681: }
0682: int i;
0683: while ((i = s.indexOf(';')) >= 0)
0684: s = s.substring(0, i) + s.substring(i + 1);
0685: return s;
0686: }
0687: }
0688:
0689: static int compareSignatures(String s1, String s2) {
0690: return compareSignatures(s1, s2, null, null);
0691: }
0692:
0693: static int compareSignatures(String s1, String s2, String[] p1,
0694: String[] p2) {
0695: final int S1_COMES_FIRST = -1;
0696: final int S2_COMES_FIRST = +1;
0697: char c1 = s1.charAt(0);
0698: char c2 = s2.charAt(0);
0699: // fields before methods (because there are fewer of them)
0700: if (c1 != '(' && c2 == '(')
0701: return S1_COMES_FIRST;
0702: if (c2 != '(' && c1 == '(')
0703: return S2_COMES_FIRST;
0704: if (p1 == null)
0705: p1 = structureSignature(s1);
0706: if (p2 == null)
0707: p2 = structureSignature(s2);
0708: /*
0709: // non-classes before classes (because there are fewer of them)
0710: if (p1.length == 1 && p2.length > 1) return S1_COMES_FIRST;
0711: if (p2.length == 1 && p1.length > 1) return S2_COMES_FIRST;
0712: // all else being equal, use the same comparison as for Utf8 strings
0713: return s1.compareTo(s2);
0714: */
0715: if (p1.length != p2.length)
0716: return p1.length - p2.length;
0717: int length = p1.length;
0718: for (int i = length; --i >= 0;) {
0719: int res = p1[i].compareTo(p2[i]);
0720: if (res != 0)
0721: return res;
0722: }
0723: assert (s1.equals(s2));
0724: return 0;
0725: }
0726:
0727: static int countClassParts(Utf8Entry formRef) {
0728: int num = 0;
0729: String s = formRef.stringValue();
0730: for (int i = 0; i < s.length(); i++) {
0731: if (s.charAt(i) == 'L')
0732: ++num;
0733: }
0734: return num;
0735: }
0736:
0737: static String flattenSignature(String[] parts) {
0738: String form = parts[0];
0739: if (parts.length == 1)
0740: return form;
0741: int len = form.length();
0742: for (int i = 1; i < parts.length; i++) {
0743: len += parts[i].length();
0744: }
0745: char[] sig = new char[len];
0746: int j = 0;
0747: int k = 1;
0748: for (int i = 0; i < form.length(); i++) {
0749: char ch = form.charAt(i);
0750: sig[j++] = ch;
0751: if (ch == 'L') {
0752: String cls = parts[k++];
0753: cls.getChars(0, cls.length(), sig, j);
0754: j += cls.length();
0755: //sig[j++] = ';';
0756: }
0757: }
0758: assert (j == len);
0759: assert (k == parts.length);
0760: return new String(sig);
0761: }
0762:
0763: static private int skipClassNameChars(String sig, int i) {
0764: int len = sig.length();
0765: for (; i < len; i++) {
0766: char ch = sig.charAt(i);
0767: if (ch <= ' ')
0768: break;
0769: if (ch >= ';' && ch <= '@')
0770: break;
0771: }
0772: return i;
0773: }
0774:
0775: static String[] structureSignature(String sig) {
0776: sig = sig.intern();
0777:
0778: int formLen = 0;
0779: int nparts = 1;
0780: for (int i = 0; i < sig.length(); i++) {
0781: char ch = sig.charAt(i);
0782: formLen++;
0783: if (ch == 'L') {
0784: nparts++;
0785: int i2 = skipClassNameChars(sig, i + 1);
0786: i = i2 - 1; // keep the semicolon in the form
0787: int i3 = sig.indexOf('<', i + 1);
0788: if (i3 > 0 && i3 < i2)
0789: i = i3 - 1;
0790: }
0791: }
0792: char[] form = new char[formLen];
0793: if (nparts == 1) {
0794: String[] parts = { sig };
0795: return parts;
0796: }
0797: String[] parts = new String[nparts];
0798: int j = 0;
0799: int k = 1;
0800: for (int i = 0; i < sig.length(); i++) {
0801: char ch = sig.charAt(i);
0802: form[j++] = ch;
0803: if (ch == 'L') {
0804: int i2 = skipClassNameChars(sig, i + 1);
0805: parts[k++] = sig.substring(i + 1, i2);
0806: i = i2;
0807: --i; // keep the semicolon in the form
0808: }
0809: }
0810: assert (j == formLen);
0811: assert (k == parts.length);
0812: parts[0] = new String(form);
0813: //assert(flattenSignature(parts).equals(sig));
0814: return parts;
0815: }
0816:
0817: // Handy constants:
0818: protected static final Entry[] noRefs = {};
0819: protected static final ClassEntry[] noClassRefs = {};
0820:
0821: /** An Index is a mapping between CP entries and small integers. */
0822: public static class Index extends AbstractList {
0823: protected String debugName;
0824: protected Entry[] cpMap;
0825: protected boolean flattenSigs;
0826:
0827: protected Entry[] getMap() {
0828: return cpMap;
0829: }
0830:
0831: protected Index(String debugName) {
0832: this .debugName = debugName;
0833: }
0834:
0835: protected Index(String debugName, Entry[] cpMap) {
0836: this (debugName);
0837: setMap(cpMap);
0838: }
0839:
0840: protected void setMap(Entry[] cpMap) {
0841: clearIndex();
0842: this .cpMap = cpMap;
0843: }
0844:
0845: protected Index(String debugName, Collection cpMapList) {
0846: this (debugName);
0847: setMap(cpMapList);
0848: }
0849:
0850: protected void setMap(Collection cpMapList) {
0851: cpMap = new Entry[cpMapList.size()];
0852: cpMapList.toArray(cpMap);
0853: setMap(cpMap);
0854: }
0855:
0856: public int size() {
0857: return cpMap.length;
0858: }
0859:
0860: public Object get(int i) {
0861: return cpMap[i];
0862: }
0863:
0864: public Entry getEntry(int i) {
0865: // same as get(), with covariant return type
0866: return cpMap[i];
0867: }
0868:
0869: // Find index of e in cpMap, or return -1 if none.
0870: //
0871: // As a special hack, if flattenSigs, signatures are
0872: // treated as equivalent entries of cpMap. This is wrong
0873: // fron a Collection point of view, because contains()
0874: // reports true for signatures, but the iterator()
0875: // never produces them!
0876: private int findIndexOf(Entry e) {
0877: if (indexKey == null)
0878: initializeIndex();
0879: int probe = findIndexLocation(e);
0880: if (indexKey[probe] != e) {
0881: if (flattenSigs && e.tag == CONSTANT_Signature) {
0882: SignatureEntry se = (SignatureEntry) e;
0883: return findIndexOf(se.asUtf8Entry());
0884: }
0885: return -1;
0886: }
0887: int index = indexValue[probe];
0888: assert (e.equals(cpMap[index]));
0889: return index;
0890: }
0891:
0892: public boolean contains(Entry e) {
0893: return findIndexOf(e) >= 0;
0894: }
0895:
0896: // Find index of e in cpMap. Should not return -1.
0897: public int indexOf(Entry e) {
0898: int index = findIndexOf(e);
0899: if (index < 0 && verbose() > 0) {
0900: System.out.println("not found: " + e);
0901: System.out.println(" in: " + this .dumpString());
0902: Thread.dumpStack();
0903: }
0904: assert (index >= 0);
0905: return index;
0906: }
0907:
0908: public boolean contains(Object e) {
0909: return findIndexOf((Entry) e) >= 0;
0910: }
0911:
0912: public int indexOf(Object e) {
0913: return findIndexOf((Entry) e);
0914: }
0915:
0916: public int lastIndexOf(Object e) {
0917: return indexOf(e);
0918: }
0919:
0920: public boolean assertIsSorted() {
0921: for (int i = 1; i < cpMap.length; i++) {
0922: if (cpMap[i - 1].compareTo(cpMap[i]) > 0) {
0923: System.out.println("Not sorted at " + (i - 1) + "/"
0924: + i + ": " + this .dumpString());
0925: return false;
0926: }
0927: }
0928: return true;
0929: }
0930:
0931: // internal hash table
0932: protected Entry[] indexKey;
0933: protected int[] indexValue;
0934:
0935: protected void clearIndex() {
0936: indexKey = null;
0937: indexValue = null;
0938: }
0939:
0940: private int findIndexLocation(Entry e) {
0941: int size = indexKey.length;
0942: int hash = e.hashCode();
0943: int probe = hash & (size - 1);
0944: int stride = ((hash >>> 8) | 1) & (size - 1);
0945: for (;;) {
0946: Entry e1 = indexKey[probe];
0947: if (e1 == e || e1 == null)
0948: return probe;
0949: probe += stride;
0950: if (probe >= size)
0951: probe -= size;
0952: }
0953: }
0954:
0955: private void initializeIndex() {
0956: if (verbose() > 2)
0957: System.out.println("initialize Index " + debugName
0958: + " [" + size() + "]");
0959: int hsize0 = (int) ((cpMap.length + 10) * 1.5);
0960: int hsize = 1;
0961: while (hsize < hsize0)
0962: hsize <<= 1;
0963: indexKey = new Entry[hsize];
0964: indexValue = new int[hsize];
0965: for (int i = 0; i < cpMap.length; i++) {
0966: Entry e = cpMap[i];
0967: if (e == null)
0968: continue;
0969: int probe = findIndexLocation(e);
0970: assert (indexKey[probe] == null); // e has unique index
0971: indexKey[probe] = e;
0972: indexValue[probe] = i;
0973: }
0974: }
0975:
0976: public Object[] toArray(Object[] a) {
0977: int sz = size();
0978: if (a.length < sz)
0979: return super .toArray(a);
0980: System.arraycopy(cpMap, 0, a, 0, sz);
0981: if (a.length > sz)
0982: a[sz] = null;
0983: return a;
0984: }
0985:
0986: public Object[] toArray() {
0987: return toArray(new Entry[size()]);
0988: }
0989:
0990: public Object clone() {
0991: return new Index(debugName, (Entry[]) cpMap.clone());
0992: }
0993:
0994: public String toString() {
0995: return "Index " + debugName + " [" + size() + "]";
0996: }
0997:
0998: public String dumpString() {
0999: String s = toString();
1000: s += " {\n";
1001: for (int i = 0; i < cpMap.length; i++) {
1002: s += " " + i + ": " + cpMap[i] + "\n";
1003: }
1004: s += "}";
1005: return s;
1006: }
1007: }
1008:
1009: // Index methods.
1010:
1011: public static Index makeIndex(String debugName, Entry[] cpMap) {
1012: return new Index(debugName, cpMap);
1013: }
1014:
1015: public static Index makeIndex(String debugName, Collection cpMapList) {
1016: return new Index(debugName, cpMapList);
1017: }
1018:
1019: /** Sort this index (destructively) into canonical order. */
1020: public static void sort(Index ix) {
1021: // %%% Should move this into class Index.
1022: ix.clearIndex();
1023: Arrays.sort(ix.cpMap);
1024: if (verbose() > 2)
1025: System.out.println("sorted " + ix.dumpString());
1026: }
1027:
1028: /** Return a set of indexes partitioning these entries.
1029: * The keys array must of length this.size(), and marks entries.
1030: * The result array is as long as one plus the largest key value.
1031: * Entries with a negative key are dropped from the partition.
1032: */
1033: public static Index[] partition(Index ix, int[] keys) {
1034: // %%% Should move this into class Index.
1035: ArrayList parts = new ArrayList();
1036: Entry[] cpMap = ix.cpMap;
1037: assert (keys.length == cpMap.length);
1038: for (int i = 0; i < keys.length; i++) {
1039: int key = keys[i];
1040: if (key < 0)
1041: continue;
1042: while (key >= parts.size())
1043: parts.add(null);
1044: ArrayList part = (ArrayList) parts.get(key);
1045: if (part == null) {
1046: parts.set(key, part = new ArrayList());
1047: }
1048: part.add(cpMap[i]);
1049: }
1050: Index[] indexes = new Index[parts.size()];
1051: for (int key = 0; key < indexes.length; key++) {
1052: ArrayList part = (ArrayList) parts.get(key);
1053: if (part == null)
1054: continue;
1055: indexes[key] = new Index(ix.debugName + "/part#" + key,
1056: part);
1057: assert (indexes[key].indexOf(part.get(0)) == 0);
1058: }
1059: return indexes;
1060: }
1061:
1062: public static Index[] partitionByTag(Index ix) {
1063: // Partition by tag.
1064: Entry[] cpMap = ix.cpMap;
1065: int[] keys = new int[cpMap.length];
1066: for (int i = 0; i < keys.length; i++) {
1067: Entry e = cpMap[i];
1068: keys[i] = (e == null) ? -1 : e.tag;
1069: }
1070: Index[] byTag = partition(ix, keys);
1071: for (int tag = 0; tag < byTag.length; tag++) {
1072: if (byTag[tag] == null)
1073: continue;
1074: byTag[tag].debugName = tagName(tag);
1075: }
1076: if (byTag.length < CONSTANT_Limit) {
1077: Index[] longer = new Index[CONSTANT_Limit];
1078: System.arraycopy(byTag, 0, longer, 0, byTag.length);
1079: byTag = longer;
1080: }
1081: return byTag;
1082: }
1083:
1084: /** Coherent group of constant pool indexes. */
1085: public static class IndexGroup {
1086: private Index indexUntyped;
1087: private Index[] indexByTag = new Index[CONSTANT_Limit];
1088: private int[] untypedFirstIndexByTag;
1089: private int totalSize;
1090: private Index[][] indexByTagAndClass;
1091:
1092: /** Index of all CP entries of all types, in definition order. */
1093: public Index getUntypedIndex() {
1094: if (indexUntyped == null) {
1095: untypedIndexOf(null); // warm up untypedFirstIndexByTag
1096: Entry[] cpMap = new Entry[totalSize];
1097: for (int tag = 0; tag < indexByTag.length; tag++) {
1098: Index ix = indexByTag[tag];
1099: if (ix == null)
1100: continue;
1101: int ixLen = ix.cpMap.length;
1102: if (ixLen == 0)
1103: continue;
1104: int fillp = untypedFirstIndexByTag[tag];
1105: assert (cpMap[fillp] == null);
1106: assert (cpMap[fillp + ixLen - 1] == null);
1107: System.arraycopy(ix.cpMap, 0, cpMap, fillp, ixLen);
1108: }
1109: indexUntyped = new Index("untyped", cpMap);
1110: }
1111: return indexUntyped;
1112: }
1113:
1114: public int untypedIndexOf(Entry e) {
1115: if (untypedFirstIndexByTag == null) {
1116: untypedFirstIndexByTag = new int[CONSTANT_Limit];
1117: int fillp = 0;
1118: for (int i = 0; i < TAGS_IN_ORDER.length; i++) {
1119: byte tag = TAGS_IN_ORDER[i];
1120: Index ix = indexByTag[tag];
1121: if (ix == null)
1122: continue;
1123: int ixLen = ix.cpMap.length;
1124: untypedFirstIndexByTag[tag] = fillp;
1125: fillp += ixLen;
1126: }
1127: totalSize = fillp;
1128: }
1129: if (e == null)
1130: return -1;
1131: int tag = e.tag;
1132: Index ix = indexByTag[tag];
1133: if (ix == null)
1134: return -1;
1135: int idx = ix.findIndexOf(e);
1136: if (idx >= 0)
1137: idx += untypedFirstIndexByTag[tag];
1138: return idx;
1139: }
1140:
1141: public void initIndexByTag(byte tag, Index ix) {
1142: assert (indexByTag[tag] == null); // do not init twice
1143: Entry[] cpMap = ix.cpMap;
1144: for (int i = 0; i < cpMap.length; i++) {
1145: // It must be a homogeneous Entry set.
1146: assert (cpMap[i].tag == tag);
1147: }
1148: if (tag == CONSTANT_Utf8) {
1149: // Special case: First Utf8 must always be empty string.
1150: assert (cpMap.length == 0 || cpMap[0].stringValue()
1151: .equals(""));
1152: }
1153: indexByTag[tag] = ix;
1154: // decache indexes derived from this one:
1155: untypedFirstIndexByTag = null;
1156: indexUntyped = null;
1157: if (indexByTagAndClass != null)
1158: indexByTagAndClass[tag] = null;
1159: }
1160:
1161: /** Index of all CP entries of a given tag. */
1162: public Index getIndexByTag(byte tag) {
1163: if (tag == CONSTANT_All) {
1164: return getUntypedIndex();
1165: }
1166: Index ix = indexByTag[tag];
1167: if (ix == null) {
1168: // Make an empty one by default.
1169: ix = new Index(tagName(tag), new Entry[0]);
1170: indexByTag[tag] = ix;
1171: }
1172: return ix;
1173: }
1174:
1175: /** Index of all CP entries of a given tag and class. */
1176: public Index getMemberIndex(byte tag, ClassEntry classRef) {
1177: if (indexByTagAndClass == null)
1178: indexByTagAndClass = new Index[CONSTANT_Limit][];
1179: Index allClasses = getIndexByTag(CONSTANT_Class);
1180: Index[] perClassIndexes = indexByTagAndClass[tag];
1181: if (perClassIndexes == null) {
1182: // Create the partition now.
1183: // Divide up all entries of the given tag according to their class.
1184: Index allMembers = getIndexByTag(tag);
1185: int[] whichClasses = new int[allMembers.size()];
1186: for (int i = 0; i < whichClasses.length; i++) {
1187: MemberEntry e = (MemberEntry) allMembers.get(i);
1188: int whichClass = allClasses.indexOf(e.classRef);
1189: whichClasses[i] = whichClass;
1190: }
1191: perClassIndexes = partition(allMembers, whichClasses);
1192: for (int i = 0; i < perClassIndexes.length; i++)
1193: assert (perClassIndexes[i] == null || perClassIndexes[i]
1194: .assertIsSorted());
1195: indexByTagAndClass[tag] = perClassIndexes;
1196: }
1197: int whichClass = allClasses.indexOf(classRef);
1198: return perClassIndexes[whichClass];
1199: }
1200:
1201: // Given the sequence of all methods of the given name and class,
1202: // produce the ordinal of this particular given overloading.
1203: public int getOverloadingIndex(MemberEntry methodRef) {
1204: Index ix = getMemberIndex(methodRef.tag, methodRef.classRef);
1205: Utf8Entry nameRef = methodRef.descRef.nameRef;
1206: int ord = 0;
1207: for (int i = 0; i < ix.cpMap.length; i++) {
1208: MemberEntry e = (MemberEntry) ix.cpMap[i];
1209: if (e.equals(methodRef))
1210: return ord;
1211: if (e.descRef.nameRef.equals(nameRef))
1212: // Found a different overloading. Increment the ordinal.
1213: ord++;
1214: }
1215: throw new RuntimeException("should not reach here");
1216: }
1217:
1218: // Inverse of getOverloadingIndex
1219: public MemberEntry getOverloadingForIndex(byte tag,
1220: ClassEntry classRef, String name, int which) {
1221: assert (name == name.intern());
1222: Index ix = getMemberIndex(tag, classRef);
1223: int ord = 0;
1224: for (int i = 0; i < ix.cpMap.length; i++) {
1225: MemberEntry e = (MemberEntry) ix.cpMap[i];
1226: if (e.descRef.nameRef.stringValue() == name) {
1227: if (ord == which)
1228: return e;
1229: ord++;
1230: }
1231: }
1232: throw new RuntimeException("should not reach here");
1233: }
1234:
1235: public boolean haveNumbers() {
1236: for (byte tag = CONSTANT_Integer; tag <= CONSTANT_Double; tag++) {
1237: switch (tag) {
1238: case CONSTANT_Integer:
1239: case CONSTANT_Float:
1240: case CONSTANT_Long:
1241: case CONSTANT_Double:
1242: break;
1243: default:
1244: assert (false);
1245: }
1246: if (getIndexByTag(tag).size() > 0)
1247: return true;
1248: }
1249: return false;
1250: }
1251:
1252: }
1253:
1254: /** Close the set cpRefs under the getRef(*) relation.
1255: * Also, if flattenSigs, replace all signatures in cpRefs
1256: * by their equivalent Utf8s.
1257: * Also, discard null from cpRefs.
1258: */
1259: public static void completeReferencesIn(Set cpRefs,
1260: boolean flattenSigs) {
1261: cpRefs.remove(null);
1262: for (ListIterator work = new ArrayList(cpRefs)
1263: .listIterator(cpRefs.size()); work.hasPrevious();) {
1264: Entry e = (Entry) work.previous();
1265: work.remove(); // pop stack
1266: assert (e != null);
1267: if (flattenSigs && e.tag == CONSTANT_Signature) {
1268: SignatureEntry se = (SignatureEntry) e;
1269: Utf8Entry ue = se.asUtf8Entry();
1270: // Totally replace e by se.
1271: cpRefs.remove(se);
1272: cpRefs.add(ue);
1273: e = ue; // do not descend into the sig
1274: }
1275: // Recursively add the refs of e to cpRefs:
1276: for (int i = 0;; i++) {
1277: Entry re = e.getRef(i);
1278: if (re == null)
1279: break; // no more refs in e
1280: if (cpRefs.add(re)) // output the ref
1281: work.add(re); // push stack, if a new ref
1282: }
1283: }
1284: }
1285:
1286: static double percent(int num, int den) {
1287: return (int) ((10000.0 * num) / den + 0.5) / 100.0;
1288: }
1289:
1290: public static String tagName(int tag) {
1291: switch (tag) {
1292: case CONSTANT_Utf8:
1293: return "Utf8";
1294: case CONSTANT_Integer:
1295: return "Integer";
1296: case CONSTANT_Float:
1297: return "Float";
1298: case CONSTANT_Long:
1299: return "Long";
1300: case CONSTANT_Double:
1301: return "Double";
1302: case CONSTANT_Class:
1303: return "Class";
1304: case CONSTANT_String:
1305: return "String";
1306: case CONSTANT_Fieldref:
1307: return "Fieldref";
1308: case CONSTANT_Methodref:
1309: return "Methodref";
1310: case CONSTANT_InterfaceMethodref:
1311: return "InterfaceMethodref";
1312: case CONSTANT_NameandType:
1313: return "NameandType";
1314:
1315: // pseudo-tags:
1316: case CONSTANT_All:
1317: return "*All";
1318: case CONSTANT_None:
1319: return "*None";
1320: case CONSTANT_Signature:
1321: return "*Signature";
1322: }
1323: return "tag#" + tag;
1324: }
1325:
1326: // archive constant pool definition order
1327: static final byte TAGS_IN_ORDER[] = {
1328: CONSTANT_Utf8,
1329: CONSTANT_Integer, // cp_Int
1330: CONSTANT_Float, CONSTANT_Long, CONSTANT_Double,
1331: CONSTANT_String, CONSTANT_Class, CONSTANT_Signature,
1332: CONSTANT_NameandType, // cp_Descr
1333: CONSTANT_Fieldref, // cp_Field
1334: CONSTANT_Methodref, // cp_Method
1335: CONSTANT_InterfaceMethodref // cp_Imethod
1336: };
1337: static final byte TAG_ORDER[];
1338: static {
1339: TAG_ORDER = new byte[CONSTANT_Limit];
1340: for (int i = 0; i < TAGS_IN_ORDER.length; i++) {
1341: TAG_ORDER[TAGS_IN_ORDER[i]] = (byte) (i + 1);
1342: }
1343: /*
1344: System.out.println("TAG_ORDER[] = {");
1345: for (int i = 0; i < TAG_ORDER.length; i++)
1346: System.out.println(" "+TAG_ORDER[i]+",");
1347: System.out.println("};");
1348: */
1349: }
1350: }
|