summaryrefslogtreecommitdiff
path: root/sources/scalac/symtab/classfile/ConstantPool.java
diff options
context:
space:
mode:
Diffstat (limited to 'sources/scalac/symtab/classfile/ConstantPool.java')
-rw-r--r--sources/scalac/symtab/classfile/ConstantPool.java183
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;
+ }
+ }
+}