diff options
Diffstat (limited to 'sources/scalac/symtab/classfile/ConstantPool.java')
-rw-r--r-- | sources/scalac/symtab/classfile/ConstantPool.java | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/sources/scalac/symtab/classfile/ConstantPool.java b/sources/scalac/symtab/classfile/ConstantPool.java new file mode 100644 index 0000000000..4260b9e6ad --- /dev/null +++ b/sources/scalac/symtab/classfile/ConstantPool.java @@ -0,0 +1,183 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.*; +import scalac.symtab.*; +import scalac.util.*; + +public class ConstantPool implements ClassfileConstants { + + AbstractFileReader in; + Signatures sigparser; + + /** the objects of the constant pool + */ + protected Object[] poolObj; + + /** for every constant pool entry, an index into in.buf where the + * defining section of the entry is found + */ + protected int[] poolIdx; + + /** constructor + */ + protected ConstantPool(AbstractFileReader in, Signatures sigparser) { + this.in = in; + this.sigparser = sigparser; + } + + /** index all constant pool entries, writing their start + * addresses into poolIdx + */ + public void indexPool() { + poolIdx = new int[in.nextChar()]; + poolObj = new Object[poolIdx.length]; + int i = 1; + while (i < poolIdx.length) { + poolIdx[i++] = in.bp; + byte tag = in.nextByte(); + switch (tag) { + case CONSTANT_UTF8: + case CONSTANT_UNICODE: { + int len = in.nextChar(); + in.skip(len); + break; + } + case CONSTANT_CLASS: + case CONSTANT_STRING: + in.skip(2); + break; + case CONSTANT_FIELDREF: + case CONSTANT_METHODREF: + case CONSTANT_INTFMETHODREF: + case CONSTANT_NAMEANDTYPE: + case CONSTANT_INTEGER: + case CONSTANT_FLOAT: + in.skip(4); + break; + case CONSTANT_LONG: + case CONSTANT_DOUBLE: + in.skip(8); + i++; + break; + default: + throw new RuntimeException("bad constant pool tag: " + tag + + " at " + (in.bp - 1)); + } + } + } + + /** if name is an array type or class signature, return the + * corresponding type; otherwise return a class definition with given name + */ + protected Object classOrType(Name name) { + if ((name.sub(0) == '[') || (name.sub(name.length() - 1) == ';')) { + byte[] ascii = name.toAscii(); + return sigparser.sigToType(ascii, 0, ascii.length); + } else + return name; + } + + /** read constant pool entry at start address i, use poolObj as a cache. + */ + public Object readPool(int i) { + if (poolObj[i] != null) + return poolObj[i]; + int index = poolIdx[i]; + if (index == 0) + return null; + switch (in.byteAt(index)) { + case CONSTANT_UTF8: + poolObj[i] = Name.fromAscii(in.buf, index + 3, in.getChar(index + 1)); + break; + + case CONSTANT_UNICODE: + throw new RuntimeException("can't read unicode strings in classfiles"); + + case CONSTANT_CLASS: + poolObj[i] = classOrType(readExternal(in.getChar(index + 1))); + break; + + case CONSTANT_FIELDREF: { + //Symbol owner = (Symbol)readPool(in.getChar(index + 1)); + //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3)); + //poolObj[i] = new TermSymbol(Kinds.VAR, Position.NOPOS, nt.name, owner, 0) + // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length())); + throw new RuntimeException("can't read constant_fieldrefs in classfiles"); + } + + case CONSTANT_METHODREF: + case CONSTANT_INTFMETHODREF: { + //Symbol owner = (Symbol)readPool(in.getChar(index + 1)); + //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3)); + //poolObj[i] = new TermSymbol(Kinds.FUN, Position.NOPOS, nt.name, owner, 0) + // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length())); + throw new RuntimeException("can't read constant_methodrefs in classfiles"); + } + + case CONSTANT_NAMEANDTYPE: + poolObj[i] = new NameAndType((Name)readPool(in.getChar(index + 1)), + readExternal(in.getChar(index + 3))); + break; + + case CONSTANT_STRING: + case CONSTANT_INTEGER: + case CONSTANT_FLOAT: + case CONSTANT_LONG: + case CONSTANT_DOUBLE: + throw new RuntimeException("can't read constants in classfiles"); + + default: + throw new RuntimeException("bad constant pool tag: " + in.byteAt(index)); + } + return poolObj[i]; + } + + /** return internal representation of buf[offset..offset+len-1], + * converting '/' to '.' + */ + public byte[] internalize(byte[] buf, int offset, int len) { + byte[] translated = new byte[len]; + for (int j = 0; j < len; j++) { + byte b = buf[offset + j]; + if (b == '/') + translated[j] = '.'; + else + translated[j] = b; + } + return translated; + } + + /** read a constant pool string and convert to internal representation. + */ + public Name readExternal(int i) { + if (poolObj[i] == null) { + int index = poolIdx[i]; + if (in.byteAt(index) == CONSTANT_UTF8) { + int len = in.getChar(index + 1); + byte[] translated = internalize(in.buf, index + 3, len); + poolObj[i] = Name.fromAscii(translated, 0, len); + } + } + return (Name)poolObj[i]; + } + + /** the name and type signature of a method or field + */ + public static final class NameAndType { + public Name name; + public Name sig; + + public NameAndType(Name name, Name sig) { + this.name = name; + this.sig = sig; + } + } +} |