001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.editor;
022:
023: import java.util.*;
024:
025: import EDU.purdue.cs.bloat.reflect.*;
026: import EDU.purdue.cs.bloat.util.*;
027:
028: /**
029: * ConstantPool models constants in the constant pool. Recall that the
030: * reflection mechanism represents constants as a tag and a value. ConstantPool
031: * consists of an array of <tt>reflect.Constant</tt>s that are resolved into
032: * their appropriate value (e.g. Type, NameAndType, MemberRef, etc.) as they are
033: * needed.
034: *
035: * @see EDU.purdue.cs.bloat.reflect.Constant
036: *
037: * @author Nate Nystrom (<a
038: * href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
039: */
040: public class ConstantPool {
041: /**
042: * ConstantPool maintains some information about the constants in the
043: * constant pool to make its life easier.
044: *
045: * constantIndices A mapping between constants and their indices in the
046: * constant pool. Knowing this information makes adding constants to the
047: * constant pool easier.
048: *
049: * constants A list of the reflect.Constant objects that are used to create
050: * the ConstantPool.
051: *
052: * resolved A list of the constants in their resolved form (such as
053: * NameAndType or String)
054: */
055: private Map constantIndices;
056:
057: ResizeableArrayList constants;
058:
059: ResizeableArrayList resolved;
060:
061: /**
062: * Constructor. Resolve the constants in the constant pool, converting from
063: * the index-based representation of the class file to a more amenable
064: * external representation.
065: *
066: * @param c
067: * An array of Constant.
068: */
069: public ConstantPool(final Constant[] c) {
070: constantIndices = new HashMap();
071: constants = new ResizeableArrayList(c.length);
072: resolved = new ResizeableArrayList(c.length);
073:
074: /*
075: * constants = new ResizeableArrayList(c.length, 256); resolved = new
076: * ResizeableArrayList(c.length, 256);
077: */
078: for (int i = 0; i < c.length; i++) {
079: constants.add(c[i]);
080: resolved.add(null);
081: if (c[i] != null) {
082: constantIndices.put(c[i], new Integer(i));
083: }
084: }
085: }
086:
087: /**
088: * Creates a new, empty <code>ConstantPool</code>
089: */
090: public ConstantPool() {
091: this .constantIndices = new HashMap();
092: this .constants = new ResizeableArrayList();
093: this .resolved = new ResizeableArrayList();
094: }
095:
096: /**
097: * Obtain the resolved value of a constant at given index in the constant
098: * pool.
099: *
100: * @param idx
101: * Index into the constant pool.
102: * @return The value of the constant at index.
103: */
104: public Object constantAt(final int idx) {
105: if (idx == 0) {
106: return null;
107: }
108:
109: Object value = resolved.get(idx);
110:
111: if (value != null) {
112: return value;
113: }
114:
115: final Constant c = (Constant) constants.get(idx);
116:
117: if (c == null) {
118: return null;
119: }
120:
121: value = c.value();
122:
123: if (value == null) {
124: return null;
125: }
126:
127: // Okay, we have to resolve the Constant.
128:
129: switch (c.tag()) {
130: case Constant.CLASS: {
131: // Lookup the UTF8 at the index and use the class name
132: // to create a Type.
133: Assert.isTrue(value instanceof Integer,
134: "Invalid constant: " + c);
135:
136: final int index = ((Integer) value).intValue();
137: Assert.isTrue(constantTag(index) == Constant.UTF8,
138: "Invalid constant: " + c);
139:
140: final String className = (String) constantAt(index);
141:
142: value = Type.getType(Type.classDescriptor(className));
143: break;
144: }
145: case Constant.STRING: {
146: // Lookup the UTF8 at the index and store the String directly.
147: Assert.isTrue(value instanceof Integer,
148: "Invalid constant: " + c);
149:
150: final int index = ((Integer) value).intValue();
151: Assert.isTrue(constantTag(index) == Constant.UTF8,
152: "Invalid constant: " + c);
153:
154: value = constantAt(index);
155: break;
156: }
157: case Constant.FIELD_REF:
158: case Constant.METHOD_REF:
159: case Constant.INTERFACE_METHOD_REF: {
160: // The constant at the first index should be a CLASS.
161: //
162: // The constant at the second should be a NAME_AND_TYPE.
163: //
164: // Resolve the two constants and then create a MemberRef
165: // for this constant.
166: //
167: Assert.isTrue(value instanceof int[], "Invalid constant: "
168: + c);
169:
170: final int[] v = (int[]) value;
171:
172: Assert.isTrue(constantTag(v[0]) == Constant.CLASS,
173: "Invalid constant: " + c);
174: Assert.isTrue(constantTag(v[1]) == Constant.NAME_AND_TYPE,
175: "Invalid constant: " + c);
176:
177: final Type clazz = (Type) constantAt(v[0]);
178: final NameAndType nameAndType = (NameAndType) constantAt(v[1]);
179:
180: value = new MemberRef(clazz, nameAndType);
181: break;
182: }
183: case Constant.NAME_AND_TYPE: {
184: // The constant at the first index should be a UTF8 with the
185: // name of the field.
186: //
187: // The constant at the second should be a UTF8 with the type
188: // of the field.
189: //
190: // Resolve the two constants as a String and a Type and then
191: // create a NameAndType for this constant.
192: //
193: Assert.isTrue(value instanceof int[], "Invalid constant: "
194: + c);
195:
196: final int[] v = (int[]) value;
197:
198: Assert.isTrue(constantTag(v[0]) == Constant.UTF8,
199: "Invalid constant: " + c);
200: Assert.isTrue(constantTag(v[1]) == Constant.UTF8,
201: "Invalid constant: " + c);
202:
203: final String name = (String) constantAt(v[0]);
204: final String type = (String) constantAt(v[1]);
205:
206: value = new NameAndType(name, Type.getType(type));
207: break;
208: }
209: default:
210: break;
211: }
212:
213: resolved.ensureSize(idx + 1);
214: resolved.set(idx, value);
215:
216: return value;
217: }
218:
219: public int numConstants() {
220: return constants.size();
221: }
222:
223: /**
224: * Get the tag of a constant.
225: *
226: * @param index
227: * Index into the constant pool.
228: * @return The tag of the constant at index, or Constant.UTF8.
229: */
230: public int constantTag(final int index) {
231: if ((0 < index) && (index < constants.size())) {
232: final Constant c = (Constant) constants.get(index);
233:
234: if (c != null) {
235: return c.tag();
236: }
237: }
238:
239: return Constant.UTF8;
240: }
241:
242: /**
243: * Get the index of the constant with the given tag and value.
244: *
245: * @param tag
246: * The constant's tag (for example, <tt>Constant.UTF8</tt>).
247: * @param value
248: * The constant's value (for example, a <tt>String</tt>).
249: * @return The index of the constant.
250: */
251: public int constantIndex(final int tag, final Object value) {
252: return addConstant(tag, value);
253: }
254:
255: /**
256: * Returns the index of the constant pool entry for the given class
257: */
258: public int getClassIndex(final Class c) {
259: return (addConstant(Constant.CLASS, Type.getType(c)));
260: }
261:
262: /**
263: * Returns the index of the constant pool entry for the given integer
264: */
265: public int getIntegerIndex(final Integer i) {
266: return (addConstant(Constant.INTEGER, i));
267: }
268:
269: /**
270: * Returns the index of the constant pool entry for the given float
271: */
272: public int getFloatIndex(final Float f) {
273: return (addConstant(Constant.FLOAT, f));
274: }
275:
276: /**
277: * Returns the index of the constant pool entry for the given long
278: */
279: public int getLongIndex(final Long l) {
280: return (addConstant(Constant.LONG, l));
281: }
282:
283: /**
284: * Returns the index of the constant pool entry for the given double
285: */
286: public int getDoubleIndex(final Double d) {
287: return (addConstant(Constant.DOUBLE, d));
288: }
289:
290: /**
291: * Returns the index of the constant pool entry for the given class.
292: */
293: public int getClassIndex(final Type type) {
294: Assert.isTrue(type.isObject(), "Type " + type
295: + " is not an class type");
296: // Make sure that the descriptor constant is also there
297: getTypeIndex(type);
298: return (addConstant(Constant.CLASS, type));
299: }
300:
301: /**
302: * Returns the index of the constant pool entry for the given
303: * <code>Type</code>
304: */
305: public int getTypeIndex(final Type type) {
306: return (addConstant(Constant.UTF8, type.descriptor()));
307: }
308:
309: /**
310: * Returns the index of the constant pool entry for the given String
311: */
312: public int getStringIndex(final String s) {
313: return (addConstant(Constant.STRING, s));
314: }
315:
316: /**
317: * Returns the index of the constant pool entry for the given
318: * <code>MemberRef</code>
319: */
320: public int getMemberRefIndex(final MemberRef ref) {
321: return (addConstant(Constant.FIELD_REF, ref));
322: }
323:
324: /**
325: * Returns the index of the constant pool entry for the given
326: * <code>NameAndType</code>
327: */
328: public int getNameAndTypeIndex(final NameAndType nat) {
329: return (addConstant(Constant.NAME_AND_TYPE, nat));
330: }
331:
332: /**
333: * Returns the index of the constant pool entry for the given UTF8 string
334: */
335: public int getUTF8Index(final String s) {
336: return (addConstant(Constant.UTF8, s));
337: }
338:
339: /**
340: * Add a constant to the constant pool. Will not add the same constant
341: * twice.
342: *
343: * @param tag
344: * The constant's tag (for example, <tt>Constant.UTF8</tt>).
345: * @param value
346: * The constant's value (for example, a <tt>String</tt>).
347: * @return The index of the constant.
348: */
349: public int addConstant(final int tag, final Object value) {
350: if (value == null) {
351: return 0;
352: }
353:
354: Constant c;
355:
356: switch (tag) {
357: case Constant.CLASS: {
358: Assert.isTrue(value instanceof Type, "Invalid value: "
359: + value);
360: final int index = addConstant(Constant.UTF8, ((Type) value)
361: .className());
362: c = new Constant(Constant.CLASS, new Integer(index));
363: break;
364: }
365: case Constant.STRING: {
366: Assert.isTrue(value instanceof String, "Invalid value: "
367: + value);
368: final int index = addConstant(Constant.UTF8, value);
369: c = new Constant(Constant.STRING, new Integer(index));
370: break;
371: }
372: case Constant.FIELD_REF:
373: case Constant.METHOD_REF:
374: case Constant.INTERFACE_METHOD_REF: {
375: // The constant at the first index should be a CLASS.
376: //
377: // The constant at the second should be a NAME_AND_TYPE.
378: //
379: // Resolve the two constants and then create a MemberRef
380: // for this constant.
381: //
382: Assert.isTrue(value instanceof MemberRef, "Invalid value: "
383: + value);
384:
385: final int[] v = new int[2];
386:
387: v[0] = addConstant(Constant.CLASS, ((MemberRef) value)
388: .declaringClass());
389: v[1] = addConstant(Constant.NAME_AND_TYPE,
390: ((MemberRef) value).nameAndType());
391:
392: c = new Constant(tag, v);
393: break;
394: }
395: case Constant.NAME_AND_TYPE: {
396: // The constant at the first index should be a UTF8 with the
397: // name of the field.
398: //
399: // The constant at the second should be a UTF8 with the type
400: // of the field.
401: //
402: // Resolve the two constants as a String and a Type and then
403: // create a NameAndType for this constant.
404: //
405: Assert.isTrue(value instanceof NameAndType,
406: "Invalid value: " + value);
407:
408: final int[] v = new int[2];
409:
410: v[0] = addConstant(Constant.UTF8, ((NameAndType) value)
411: .name());
412: v[1] = addConstant(Constant.UTF8, ((NameAndType) value)
413: .type().descriptor());
414:
415: c = new Constant(tag, v);
416: break;
417: }
418: case Constant.UTF8: {
419: final String s = (String) value;
420: c = new Constant(tag, s.intern());
421: break;
422: }
423: default: {
424: c = new Constant(tag, value);
425: break;
426: }
427: }
428:
429: Integer index = (Integer) constantIndices.get(c);
430:
431: if (index == null) {
432: index = new Integer(constants.size());
433: constantIndices.put(c, index);
434: constants.add(c);
435: resolved.add(value);
436:
437: if ((tag == Constant.LONG) || (tag == Constant.DOUBLE)) {
438: constants.add(null);
439: resolved.add(null);
440: }
441: }
442:
443: return index.intValue();
444: }
445:
446: /**
447: * Get an array of the constants in the pool.
448: *
449: * @return An array of the constants in the pool.
450: */
451: public Constant[] constants() {
452: final Object[] a = constants.toArray();
453: final Constant[] array = new Constant[a.length];
454: System.arraycopy(a, 0, array, 0, a.length);
455: return array;
456: }
457:
458: /**
459: * Returns an unmodifiable List of constants in this constant pool.
460: */
461: public List getConstantsList() {
462: return Collections.unmodifiableList(this.constants);
463: }
464: }
|