001: // Copyright (c) 1997 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: /** Manages a pool of constants, as used in .class files and Java interpreters.
007: * @author Per Bothner
008: */
009:
010: public class ConstantPool {
011: static public final byte CLASS = 7;
012: static public final byte FIELDREF = 9;
013: static public final byte METHODREF = 10;
014: static public final byte INTERFACE_METHODREF = 11;
015: static public final byte STRING = 8;
016: static public final byte INTEGER = 3;
017: static public final byte FLOAT = 4;
018: static public final byte LONG = 5;
019: static public final byte DOUBLE = 6;
020: static public final byte NAME_AND_TYPE = 12;
021: static public final byte UTF8 = 1;
022:
023: /** The entries in the constant pool.
024: * The first element (constant_pool[0]) is an unused dummy. */
025: CpoolEntry[] pool;
026:
027: /** Number of elements in the constant pool, not counting
028: * the initial dummy element (with index 0). */
029: int count;
030:
031: public final int getCount() {
032: return count;
033: }
034:
035: /**
036: * Get the index'th entry in pool.
037: * Will throw ArrayIndexOutOfBoundsException on an invalid index
038: */
039: public final CpoolEntry getPoolEntry(int index) {
040: return pool[index];
041: }
042:
043: boolean locked;
044:
045: CpoolEntry[] hashTab;
046:
047: void rehash() {
048: if (hashTab == null && count > 0) {
049: // Entries may not have been hashed before. Make sure they are now.
050: for (int i = pool.length; --i >= 0;) {
051: CpoolEntry entry = pool[i];
052: // Make sure entry.hash is not the default value 0.
053: if (entry != null)
054: entry.hashCode();
055: }
056: }
057:
058: hashTab = new CpoolEntry[count < 5 ? 101 : 2 * count];
059: if (pool != null) {
060: for (int i = pool.length; --i >= 0;) {
061: CpoolEntry entry = pool[i];
062: if (entry != null)
063: entry.add_hashed(this );
064: }
065: }
066: }
067:
068: public CpoolUtf8 addUtf8(String s) {
069: s = s.intern();
070: int h = s.hashCode();
071:
072: // Check if we already have a matching CONSTANT_Utf8.
073: if (hashTab == null)
074: rehash();
075:
076: int index = (h & 0x7FFFFFFF) % hashTab.length;
077: for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next) {
078: if (h == entry.hash && entry instanceof CpoolUtf8) {
079: CpoolUtf8 utf = (CpoolUtf8) entry;
080: if (utf.string == s)
081: return utf;
082: }
083: }
084: if (locked)
085: throw new Error(
086: "adding new Utf8 entry to locked contant pool: "
087: + s);
088: return new CpoolUtf8(this , h, s);
089: }
090:
091: public CpoolClass addClass(ObjectType otype) {
092: return addClass(addUtf8(otype.getInternalName()));
093: }
094:
095: public CpoolClass addClass(String name) {
096: return addClass(addUtf8(name.replace('.', '/')));
097: }
098:
099: public CpoolClass addClass(CpoolUtf8 name) {
100: int h = CpoolClass.hashCode(name);
101:
102: // Check if we already have a matching CONSTANT_Class.
103: if (hashTab == null)
104: rehash();
105: int index = (h & 0x7FFFFFFF) % hashTab.length;
106: for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next) {
107: if (h == entry.hash && entry instanceof CpoolClass) {
108: CpoolClass ent = (CpoolClass) entry;
109: if (ent.name == name)
110: return ent;
111: }
112: }
113: return new CpoolClass(this , h, name);
114: }
115:
116: CpoolValue1 addValue1(int tag, int val) {
117: int h = CpoolValue1.hashCode(val);
118:
119: // Check if we already have a matching CONSTANT_Integer.
120: if (hashTab == null)
121: rehash();
122: int index = (h & 0x7FFFFFFF) % hashTab.length;
123: for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next) {
124: if (h == entry.hash && entry instanceof CpoolValue1) {
125: CpoolValue1 ent = (CpoolValue1) entry;
126: if (ent.tag == tag && ent.value == val)
127: return ent;
128: }
129: }
130: return new CpoolValue1(this , tag, h, val);
131: }
132:
133: CpoolValue2 addValue2(int tag, long val) {
134: int h = CpoolValue2.hashCode(val);
135:
136: // Check if we already have a matching CONSTANT_Integer.
137: if (hashTab == null)
138: rehash();
139: int index = (h & 0x7FFFFFFF) % hashTab.length;
140: for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next) {
141: if (h == entry.hash && entry instanceof CpoolValue2) {
142: CpoolValue2 ent = (CpoolValue2) entry;
143: if (ent.tag == tag && ent.value == val)
144: return ent;
145: }
146: }
147: return new CpoolValue2(this , tag, h, val);
148: }
149:
150: public CpoolValue1 addInt(int val) {
151: return addValue1(INTEGER, val);
152: }
153:
154: public CpoolValue2 addLong(long val) {
155: return addValue2(LONG, val);
156: }
157:
158: public CpoolValue1 addFloat(float val) {
159: return addValue1(FLOAT, Float.floatToIntBits(val));
160: }
161:
162: public CpoolValue2 addDouble(double val) {
163: return addValue2(DOUBLE, Double.doubleToLongBits(val));
164: }
165:
166: public final CpoolString addString(String string) {
167: return addString(addUtf8(string));
168: }
169:
170: public CpoolString addString(CpoolUtf8 str) {
171: int h = CpoolString.hashCode(str);
172:
173: // Check if we already have a matching CONSTANT_String.
174: if (hashTab == null)
175: rehash();
176: int index = (h & 0x7FFFFFFF) % hashTab.length;
177: for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next) {
178: if (h == entry.hash && entry instanceof CpoolString) {
179: CpoolString ent = (CpoolString) entry;
180: if (ent.str == str)
181: return ent;
182: }
183: }
184: return new CpoolString(this , h, str);
185: }
186:
187: public CpoolNameAndType addNameAndType(Method method) {
188: CpoolUtf8 name = addUtf8(method.getName());
189: CpoolUtf8 type = addUtf8(method.getSignature());
190: return addNameAndType(name, type);
191: }
192:
193: public CpoolNameAndType addNameAndType(Field field) {
194: CpoolUtf8 name = addUtf8(field.getName());
195: CpoolUtf8 type = addUtf8(field.getSignature());
196: return addNameAndType(name, type);
197: }
198:
199: public CpoolNameAndType addNameAndType(CpoolUtf8 name,
200: CpoolUtf8 type) {
201: int h = CpoolNameAndType.hashCode(name, type);
202:
203: // Check if we already have a matching CONSTANT_Integer.
204: if (hashTab == null)
205: rehash();
206: int index = (h & 0x7FFFFFFF) % hashTab.length;
207: for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next) {
208: if (h == entry.hash && entry instanceof CpoolNameAndType
209: && ((CpoolNameAndType) entry).name == name
210: && ((CpoolNameAndType) entry).type == type)
211: return (CpoolNameAndType) entry;
212: }
213: return new CpoolNameAndType(this , h, name, type);
214: }
215:
216: public CpoolRef addRef(int tag, CpoolClass clas,
217: CpoolNameAndType nameAndType) {
218: int h = CpoolRef.hashCode(clas, nameAndType);
219:
220: // Check if we already have a matching CONSTANT_Integer.
221: if (hashTab == null)
222: rehash();
223: int index = (h & 0x7FFFFFFF) % hashTab.length;
224: for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next) {
225: if (h == entry.hash && entry instanceof CpoolRef) {
226: CpoolRef ref = (CpoolRef) entry;
227: if (ref.tag == tag && ref.clas == clas
228: && ref.nameAndType == nameAndType)
229: return ref;
230: }
231: }
232: return new CpoolRef(this , h, tag, clas, nameAndType);
233: }
234:
235: public CpoolRef addMethodRef(Method method) {
236: CpoolClass clas = addClass(method.classfile.this _name);
237: int tag;
238: if ((method.getDeclaringClass().getModifiers() & Access.INTERFACE) == 0)
239: tag = 10; // CONSTANT_Methodref
240: else
241: tag = 11; // CONSTANT_InterfaceMethodref
242: CpoolNameAndType nameType = addNameAndType(method);
243: return addRef(tag, clas, nameType);
244: }
245:
246: public CpoolRef addFieldRef(Field field) {
247: CpoolClass clas = addClass(field.owner.this _name);
248: int tag = 9; // CONSTANT_Fieldref
249: CpoolNameAndType nameType = addNameAndType(field);
250: return addRef(tag, clas, nameType);
251: }
252:
253: void write(java.io.DataOutputStream dstr)
254: throws java.io.IOException {
255: dstr.writeShort(count + 1);
256: for (int i = 1; i <= count; i++) {
257: CpoolEntry entry = pool[i];
258: if (entry != null)
259: entry.write(dstr);
260: }
261: locked = true;
262: }
263:
264: /** Get or create a CpoolEntry at a given index.
265: * If there is an existing entry, it must match the tag.
266: * If not, a new one is create of the class appropriate for the tag.
267: */
268: CpoolEntry getForced(int index, int tag) {
269: index = index & 0xffff;
270: CpoolEntry entry = pool[index];
271: if (entry == null) {
272: if (locked)
273: throw new Error(
274: "adding new entry to locked contant pool");
275: switch (tag) {
276: case UTF8:
277: entry = new CpoolUtf8();
278: break;
279: case INTEGER:
280: case FLOAT:
281: entry = new CpoolValue1(tag);
282: break;
283: case LONG:
284: case DOUBLE:
285: entry = new CpoolValue2(tag);
286: break;
287: case CLASS:
288: entry = new CpoolClass();
289: break;
290: case STRING:
291: entry = new CpoolString();
292: break;
293: case FIELDREF:
294: case METHODREF:
295: case INTERFACE_METHODREF:
296: entry = new CpoolRef(tag);
297: break;
298: case NAME_AND_TYPE:
299: entry = new CpoolNameAndType();
300: }
301: pool[index] = entry;
302: entry.index = index;
303: } else if (entry.getTag() != tag)
304: throw new ClassFormatError(
305: "conflicting constant pool tags at " + index);
306: return entry;
307: }
308:
309: public ConstantPool() {
310: }
311:
312: public ConstantPool(java.io.DataInputStream dstr)
313: throws java.io.IOException {
314: count = dstr.readUnsignedShort() - 1;
315: pool = new CpoolEntry[count + 1];
316: for (int i = 1; i <= count; i++) {
317: byte tag = dstr.readByte();
318: CpoolEntry entry = getForced(i, tag);
319: switch (tag) {
320: case UTF8:
321: ((CpoolUtf8) entry).string = dstr.readUTF();
322: break;
323: case INTEGER:
324: case FLOAT:
325: ((CpoolValue1) entry).value = dstr.readInt();
326: break;
327: case LONG:
328: case DOUBLE:
329: ((CpoolValue2) entry).value = dstr.readLong();
330: i++;
331: break;
332: case CLASS:
333: ((CpoolClass) entry).name = (CpoolUtf8) getForced(dstr
334: .readUnsignedShort(), UTF8);
335: break;
336: case STRING:
337: ((CpoolString) entry).str = (CpoolUtf8) getForced(dstr
338: .readUnsignedShort(), UTF8);
339: break;
340: case FIELDREF:
341: case METHODREF:
342: case INTERFACE_METHODREF:
343: CpoolRef ref = (CpoolRef) entry;
344: ref.clas = (CpoolClass) getForced(dstr
345: .readUnsignedShort(), CLASS);
346: ref.nameAndType = (CpoolNameAndType) getForced(dstr
347: .readUnsignedShort(), NAME_AND_TYPE);
348: break;
349: case NAME_AND_TYPE:
350: CpoolNameAndType ntyp = (CpoolNameAndType) entry;
351: ntyp.name = (CpoolUtf8) getForced(dstr
352: .readUnsignedShort(), UTF8);
353: ntyp.type = (CpoolUtf8) getForced(dstr
354: .readUnsignedShort(), UTF8);
355: break;
356: }
357: }
358: }
359: }
|