123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- // Copyright (c) 1997 Per M.A. Bothner.
- // This is free software; for terms and warranty disclaimer see ./COPYING.
- package gnu.bytecode;
- /** Manages a pool of constants, as used in .class files and Java interpreters.
- * @author Per Bothner
- */
- public class ConstantPool {
- static public final byte CLASS = 7;
- static public final byte FIELDREF = 9;
- static public final byte METHODREF = 10;
- static public final byte INTERFACE_METHODREF = 11;
- /** Any one of the XXX_REF types. */
- static public final byte ANY_REF = -1;
- static public final byte STRING = 8;
- static public final byte INTEGER = 3;
- static public final byte FLOAT = 4;
- static public final byte LONG = 5;
- static public final byte DOUBLE = 6;
- static public final byte METHOD_HANDLE = 15;
- static public final byte METHOD_TYPE = 16;
- static public final byte INVOKE_DYNAMIC = 18;
- static public final byte NAME_AND_TYPE = 12;
- static public final byte UTF8 = 1;
- /** The entries in the constant pool.
- * The first element (constant_pool[0]) is an unused dummy. */
- CpoolEntry[] pool;
- /** Number of elements in the constant pool, not counting
- * the initial dummy element (with index 0). */
- int count;
- public final int getCount()
- {
- return count;
- }
- /**
- * Get the index'th entry in pool.
- * Will throw ArrayIndexOutOfBoundsException on an invalid index
- */
- public final CpoolEntry getPoolEntry(int index)
- {
- return pool[index];
- }
- boolean locked;
- CpoolEntry[] hashTab;
- void rehash ()
- {
- if (hashTab == null && count > 0)
- {
- // Entries may not have been hashed before. Make sure they are now.
- for (int i = pool.length; --i >= 0; )
- {
- CpoolEntry entry = pool[i];
- // Make sure entry.hash is not the default value 0.
- if (entry != null)
- entry.hashCode();
- }
- }
- hashTab = new CpoolEntry[count < 5 ? 101 : 2 * count];
- if (pool != null)
- {
- for (int i = pool.length; --i >= 0; )
- {
- CpoolEntry entry = pool[i];
- if (entry != null)
- entry.add_hashed (this);
- }
- }
- }
- public CpoolUtf8 addUtf8 (String s)
- {
- s = s.intern();
- int h = s.hashCode();
- // Check if we already have a matching CONSTANT_Utf8.
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
- {
- if (h == entry.hash && entry instanceof CpoolUtf8)
- {
- CpoolUtf8 utf = (CpoolUtf8) entry;
- if (utf.string == s)
- return utf;
- }
- }
- if (locked)
- throw new Error("adding new Utf8 entry to locked contant pool: "+s);
- return new CpoolUtf8(this, h, s);
- }
- public CpoolClass addClass (ObjectType otype)
- {
- CpoolClass entry = addClass(addUtf8(otype.getInternalName()));
- entry.clas = otype;
- return entry;
- }
- public CpoolMethodHandle addMethodHandle(Method method) {
- int kind;
- if ((method.access_flags & Access.STATIC) != 0)
- kind = 6; // REF_invokeStatic
- else if (method.classfile.isInterface())
- kind = 9; // REF_invokeInterface
- else if ("<init>".equals(method.getName()))
- kind = 8; // REF_newInvokeSpecial
- else if ((method.access_flags & Access.PRIVATE) != 0)
- kind = 7; // REF_invokeSpecial
- else
- kind = 5; // REF_invokeVirtual
- return addMethodHandle(kind, addMethodRef(method));
- }
- public CpoolMethodHandle addMethodHandle(int kind, CpoolRef reference) {
- int h = CpoolMethodHandle.hashCode(kind, reference);
- // Check if we already have a matching CONSTANT_METHOD_HANDLE
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null;
- entry = entry.next) {
- if (h == entry.hash
- && entry instanceof CpoolMethodHandle
- && ((CpoolMethodHandle)entry).kind == kind
- && ((CpoolMethodHandle)entry).reference == reference)
- return (CpoolMethodHandle)entry;
- }
- return new CpoolMethodHandle(this, h, kind, reference);
- }
- public CpoolClass addClass (CpoolUtf8 name)
- {
- int h = CpoolClass.hashCode(name);
- // Check if we already have a matching CONSTANT_Class.
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
- {
- if (h == entry.hash && entry instanceof CpoolClass)
- {
- CpoolClass ent = (CpoolClass) entry;
- if (ent.name == name)
- return ent;
- }
- }
- return new CpoolClass (this, h, name);
- }
- CpoolValue1 addValue1 (int tag, int val)
- {
- int h = CpoolValue1.hashCode(val);
- // Check if we already have a matching CONSTANT_Integer.
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
- {
- if (h == entry.hash && entry instanceof CpoolValue1)
- {
- CpoolValue1 ent = (CpoolValue1) entry;
- if (ent.tag == tag && ent.value == val)
- return ent;
- }
- }
- return new CpoolValue1 (this, tag, h, val);
- }
- CpoolValue2 addValue2 (int tag, long val)
- {
- int h = CpoolValue2.hashCode(val);
- // Check if we already have a matching CONSTANT_Long
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
- {
- if (h == entry.hash && entry instanceof CpoolValue2)
- {
- CpoolValue2 ent = (CpoolValue2) entry;
- if (ent.tag == tag && ent.value == val)
- return ent;
- }
- }
- return new CpoolValue2 (this, tag, h, val);
- }
- public CpoolValue1 addInt (int val)
- {
- return addValue1(INTEGER, val);
- }
- public CpoolValue2 addLong (long val)
- {
- return addValue2(LONG, val);
- }
- public CpoolValue1 addFloat (float val)
- {
- return addValue1(FLOAT, Float.floatToIntBits(val));
- }
- public CpoolValue2 addDouble (double val)
- {
- return addValue2(DOUBLE, Double.doubleToLongBits(val));
- }
- public final CpoolString addString (String string)
- {
- return addString(addUtf8(string));
- }
- public CpoolString addString (CpoolUtf8 str)
- {
- int h = CpoolString.hashCode (str);
- // Check if we already have a matching CONSTANT_String.
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
- {
- if (h == entry.hash && entry instanceof CpoolString)
- {
- CpoolString ent = (CpoolString) entry;
- if (ent.str == str)
- return ent;
- }
- }
- return new CpoolString (this, h, str);
- }
- public CpoolNameAndType addNameAndType (Method method)
- {
- CpoolUtf8 name = addUtf8(method.getName());
- CpoolUtf8 type = addUtf8(method.getSignature ());
- return addNameAndType(name, type);
- }
- public CpoolNameAndType addNameAndType (Field field)
- {
- CpoolUtf8 name = addUtf8(field.getName());
- CpoolUtf8 type = addUtf8(field.getSignature ());
- return addNameAndType(name, type);
- }
- public CpoolNameAndType
- addNameAndType (CpoolUtf8 name, CpoolUtf8 type)
- {
- int h = CpoolNameAndType.hashCode (name, type);
- // Check if we already have a matching CONSTANT_NAME_AND_TYPE
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
- {
- if (h == entry.hash
- && entry instanceof CpoolNameAndType
- && ((CpoolNameAndType)entry).name == name
- && ((CpoolNameAndType)entry).type == type)
- return (CpoolNameAndType)entry;
- }
- return new CpoolNameAndType(this, h, name, type);
- }
- public CpoolRef
- addRef (int tag, CpoolClass clas, CpoolNameAndType nameAndType)
- {
- int h = CpoolRef.hashCode (clas, nameAndType);
- // Check if we already have a matching CONSTANT_Ref
- if (hashTab == null)
- rehash();
- int index = (h & 0x7FFFFFFF) % hashTab.length;
- for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
- {
- if (h == entry.hash && entry instanceof CpoolRef)
- {
- CpoolRef ref = (CpoolRef) entry;
- if (ref.tag == tag
- && ref.clas == clas
- && ref.nameAndType== nameAndType)
- return ref;
- }
- }
- return new CpoolRef (this, h, tag, clas, nameAndType);
- }
- public CpoolRef addMethodRef (Method method)
- {
- CpoolClass clas = addClass(method.classfile);
- int tag;
- if ((method.getDeclaringClass().getModifiers() & Access.INTERFACE) == 0)
- tag = 10; // CONSTANT_Methodref
- else
- tag = 11; // CONSTANT_InterfaceMethodref
- CpoolNameAndType nameType = addNameAndType(method);
- return addRef(tag, clas, nameType);
- }
- public CpoolRef addFieldRef (Field field)
- {
- CpoolClass clas = addClass(field.owner);
- int tag = 9; // CONSTANT_Fieldref
- CpoolNameAndType nameType = addNameAndType(field);
- return addRef(tag, clas, nameType);
- }
- void write (java.io.DataOutputStream dstr) throws java.io.IOException
- {
- dstr.writeShort(count+1);
- for (int i = 1; i <= count; i++)
- {
- CpoolEntry entry = pool[i];
- if (entry != null)
- entry.write (dstr);
- }
- locked = true;
- }
- /** Get or create a CpoolEntry at a given index.
- * If there is an existing entry, it must match the tag.
- * If not, a new one is create of the class appropriate for the tag.
- */
- CpoolEntry getForced(int index, int tag) {
- index = index & 0xffff;
- CpoolEntry entry = pool[index];
- if (entry == null) {
- if (locked)
- throw new Error("adding new entry to locked contant pool");
- switch (tag) {
- case UTF8: entry = new CpoolUtf8(); break;
- case INTEGER:
- case FLOAT: entry = new CpoolValue1(tag); break;
- case LONG:
- case DOUBLE: entry = new CpoolValue2(tag); break;
- case CLASS: entry = new CpoolClass(); break;
- case STRING: entry = new CpoolString(); break;
- case ANY_REF:
- case FIELDREF:
- case METHODREF:
- case INTERFACE_METHODREF: entry = new CpoolRef(tag); break;
- case NAME_AND_TYPE: entry = new CpoolNameAndType(); break;
- case INVOKE_DYNAMIC: entry = new CpoolInvokeDynamic(); break;
- case METHOD_HANDLE: entry = new CpoolMethodHandle(); break;
- case METHOD_TYPE: entry = new CpoolMethodType(); break;
- default: System.err.println("tag: "+tag);
- }
- pool[index] = entry;
- entry.index = index;
- } else if (entry.getTag() != tag) {
- if (entry.getTag() == ANY_REF)
- ((CpoolRef) entry).tag = tag;
- else if (tag != ANY_REF)
- throw new ClassFormatError("conflicting constant pool tags at "+index);
- }
- return entry;
- }
- CpoolClass getForcedClass (int index)
- {
- return (CpoolClass) getForced (index, ConstantPool.CLASS);
- }
- public ConstantPool () { }
- public ConstantPool (java.io.DataInputStream dstr)
- throws java.io.IOException
- {
- count = dstr.readUnsignedShort() - 1;
- pool = new CpoolEntry[count+1];
- for (int i = 1; i <= count; i++)
- {
- byte tag = dstr.readByte();
- CpoolEntry entry = getForced(i, tag);
- switch (tag)
- {
- case UTF8:
- ((CpoolUtf8) entry).string = dstr.readUTF();
- break;
- case INTEGER:
- case FLOAT:
- ((CpoolValue1) entry).value = dstr.readInt();
- break;
- case LONG:
- case DOUBLE:
- ((CpoolValue2) entry).value = dstr.readLong();
- i++;
- break;
- case CLASS:
- ((CpoolClass) entry).name =
- (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
- break;
- case STRING:
- ((CpoolString) entry).str =
- (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
- break;
- case FIELDREF:
- case METHODREF:
- case INTERFACE_METHODREF:
- CpoolRef ref = (CpoolRef) entry;
- ref.clas = getForcedClass(dstr.readUnsignedShort());
- ref.nameAndType = (CpoolNameAndType)
- getForced(dstr.readUnsignedShort(), NAME_AND_TYPE);
- break;
- case METHOD_HANDLE:
- CpoolMethodHandle mh = (CpoolMethodHandle) entry;
- mh.kind = dstr.readUnsignedByte();
- /*
- int kindtag = mh.kind <= 4 ? FIELDREF
- : mh.kid == 5 ? METHODREF
- : ...;
- */
- mh.reference = (CpoolRef)
- getForced(dstr.readUnsignedShort(), ANY_REF);
- break;
- case METHOD_TYPE:
- CpoolMethodType mt = (CpoolMethodType) entry;
- mt.descriptor =
- (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
- break;
- case INVOKE_DYNAMIC:
- CpoolInvokeDynamic idyn = (CpoolInvokeDynamic) entry;
- idyn.bootstrapMethodIndex = dstr.readUnsignedShort();
- idyn.nameAndType = (CpoolNameAndType)
- getForced(dstr.readUnsignedShort(), NAME_AND_TYPE);
- break;
- case NAME_AND_TYPE:
- CpoolNameAndType ntyp = (CpoolNameAndType) entry;
- ntyp.name = (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
- ntyp.type = (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
- break;
- }
- }
- }
- }
|