From 7155dffc81e96cb3f77e086d77593a511c6d80e3 Mon Sep 17 00:00:00 2001 From: paltherr Date: Sat, 13 Mar 2004 22:19:42 +0000 Subject: - Rewrote Signatures and ConstantPool to avoid ... - Rewrote Signatures and ConstantPool to avoid creation of unnecessary names --- .../scalac/symtab/classfile/AttributeParser.java | 61 ++-- .../scalac/symtab/classfile/CLRClassParser.java | 26 +- sources/scalac/symtab/classfile/ClassParser.java | 2 +- .../scalac/symtab/classfile/ClassfileParser.java | 88 +++--- sources/scalac/symtab/classfile/ConstantPool.java | 336 +++++++++++---------- .../scalac/symtab/classfile/JavaTypeCreator.java | 26 +- .../scalac/symtab/classfile/JavaTypeFactory.java | 4 +- sources/scalac/symtab/classfile/Signatures.java | 231 ++++++++------ 8 files changed, 420 insertions(+), 354 deletions(-) (limited to 'sources') diff --git a/sources/scalac/symtab/classfile/AttributeParser.java b/sources/scalac/symtab/classfile/AttributeParser.java index 5306201edd..1eafb04eea 100644 --- a/sources/scalac/symtab/classfile/AttributeParser.java +++ b/sources/scalac/symtab/classfile/AttributeParser.java @@ -75,7 +75,7 @@ public class AttributeParser implements ClassfileConstants { public Symbol readAttributes(Symbol def, Type type, int attrs) { char nattr = in.nextChar(); for (int i = 0; i < nattr; i++) { - Name attrName = (Name)pool.readPool(in.nextChar()); + Name attrName = pool.getName(in.nextChar()); int attr = nameToId(attrName); int attrLen = in.nextInt(); if ((attrs & attr) == 0) { @@ -101,31 +101,21 @@ public class AttributeParser implements ClassfileConstants { int n = in.nextChar(); //System.out.println(sym + " has " + n + " innerclass entries"); for (int i = 0; i < n; i++) { - Name name = (Name)pool.readPool(in.nextChar()); - if (name == null) { - in.nextChar(); - in.nextChar(); - in.nextChar(); - continue; - } - Symbol inner = parser.global.definitions.getClass(name); - name = (Name)pool.readPool(in.nextChar()); - if (name == null) { - in.nextChar(); - in.nextChar(); - continue; - } - Symbol outer = parser.global.definitions.getModule(name, false); - name = (Name)pool.readPool(in.nextChar()); + int inner = in.nextChar(); + if (inner == 0) { in.skip(6); return; } + int outer = in.nextChar(); + if (outer == 0) { in.skip(4); return; } + int name = in.nextChar(); + if (name == 0) { in.skip(2); return; } int flags = in.nextChar(); - if ((name == null) || - ((flags & 0x0009) == 0) || - ((flags & 0x0001) == 0) || - !outer.isModule() || - (outer != sym.dualClass().module())) - continue; - Symbol alias = outer.newTypeAlias(Position.NOPOS, - 0, name.toTypeName(), parser.make.classType(inner)); + if ((flags & JAVA_ACC_STATIC) == 0) return; + if ((flags & (JAVA_ACC_PUBLIC | JAVA_ACC_PROTECTED)) == 0) return; + if (pool.getClass(outer) != sym) return; + Symbol alias = sym.dualClass().newTypeAlias( + Position.NOPOS, + 0, + pool.getName(name).toTypeName(), + parser.make.classType(pool.getClass(inner))); parser.statics.enterNoHide(alias); } //in.skip(attrLen); @@ -159,13 +149,26 @@ public class AttributeParser implements ClassfileConstants { sym.flags |= Modifiers.DEPRECATED; return; case CONSTANT_VALUE_ATTR: - Object constVal = pool.readPool(in.nextChar()); - //System.out.println(sym.owner() + "." + sym + ": " + constVal + " of type " + constantType(type, constVal)); - sym.setInfo(parser.make.constantType(type, constVal)); + AConstant constant = pool.getConstantValue(in.nextChar()); + switch (constant) { + case INT(int value): + Definitions definitions = parser.global.definitions; + Symbol base = sym.getType().symbol(); + if (base == definitions.INT_CLASS) break; + if (base == definitions.CHAR_CLASS) + constant = AConstant.CHAR((char)value); + else if (base == definitions.SHORT_CLASS) + constant = AConstant.SHORT((short)value); + else if (base == definitions.BYTE_CLASS) + constant = AConstant.BYTE((byte)value); + else + constant = AConstant.BOOLEAN(value != 0); + } + sym.setInfo(parser.make.constantType(constant)); return; case META_ATTR: //System.out.println("parsing meta data for " + sym); - String meta = pool.readPool(in.nextChar()).toString().trim(); + String meta = pool.getString(in.nextChar()).trim(); sym.setInfo( new MetaParser(meta, tvars, sym, type).parse()); return; diff --git a/sources/scalac/symtab/classfile/CLRClassParser.java b/sources/scalac/symtab/classfile/CLRClassParser.java index ac9d630228..dc01413900 100644 --- a/sources/scalac/symtab/classfile/CLRClassParser.java +++ b/sources/scalac/symtab/classfile/CLRClassParser.java @@ -9,6 +9,7 @@ package scalac.symtab.classfile; import scalac.Global; +import scalac.atree.AConstant; import scalac.symtab.Symbol; import scalac.symtab.SymbolLoader; import scalac.symtab.TermSymbol; @@ -108,7 +109,8 @@ public class CLRClassParser extends SymbolLoader { Name name = Name.fromString(fields[i].Name); scalac.symtab.Type fieldType = getCLRType(fields[i].FieldType); if (fields[i].IsLiteral()) - fieldType = make.constantType(fieldType, fields[i].getValue()); + fieldType = make.constantType( + getConstant(fieldType.symbol(), fields[i].getValue())); Symbol owner = fields[i].IsStatic() ? staticsClass : clazz; Symbol field = new TermSymbol(Position.NOPOS, name, owner, mods); field.setInfo(fieldType); @@ -293,6 +295,28 @@ public class CLRClassParser extends SymbolLoader { return s != null ? make.classType(s) : getClassType(type); } + public AConstant getConstant(Symbol base, Object value) { + if (base == global.definitions.BOOLEAN_CLASS) + return AConstant.BOOLEAN(((Number)value).intValue() != 0); + if (base == global.definitions.BYTE_CLASS) + return AConstant.BYTE(((Number)value).byteValue()); + if (base == global.definitions.SHORT_CLASS) + return AConstant.SHORT(((Number)value).shortValue()); + if (base == global.definitions.CHAR_CLASS) + return AConstant.CHAR((char)((Number)value).intValue()); + if (base == global.definitions.INT_CLASS) + return AConstant.INT(((Number)value).intValue()); + if (base == global.definitions.LONG_CLASS) + return AConstant.LONG(((Number)value).longValue()); + if (base == global.definitions.FLOAT_CLASS) + return AConstant.FLOAT(((Number)value).floatValue()); + if (base == global.definitions.DOUBLE_CLASS) + return AConstant.DOUBLE(((Number)value).doubleValue()); + if (base == global.definitions.STRING_CLASS) + return AConstant.STRING((String)value); + throw Debug.abort("illegal value", Debug.show(value, " - ", base)); + } + protected static int translateAttributes(Type type) { int mods = Modifiers.JAVA; if (type.IsNotPublic() || type.IsNestedPrivate() diff --git a/sources/scalac/symtab/classfile/ClassParser.java b/sources/scalac/symtab/classfile/ClassParser.java index 7066a2cde4..4c40a6016c 100644 --- a/sources/scalac/symtab/classfile/ClassParser.java +++ b/sources/scalac/symtab/classfile/ClassParser.java @@ -23,7 +23,7 @@ public class ClassParser extends SymbolLoader { protected String doComplete(Symbol clasz) throws IOException { AbstractFile file = global.classPath.openFile( SourceRepresentation.externalizeFileName(clasz, ".class")); - new ClassfileParser(global,new AbstractFileReader(file),clasz).parse(); + ClassfileParser.parse(global, new AbstractFileReader(file), clasz); return "class file '" + file.getPath() + "'"; } diff --git a/sources/scalac/symtab/classfile/ClassfileParser.java b/sources/scalac/symtab/classfile/ClassfileParser.java index 5f3f2f8a57..4495e8ca74 100644 --- a/sources/scalac/symtab/classfile/ClassfileParser.java +++ b/sources/scalac/symtab/classfile/ClassfileParser.java @@ -40,34 +40,34 @@ public class ClassfileParser implements ClassfileConstants { | META_ATTR | SIG_ATTR; - protected Global global; - protected AbstractFileReader in; - protected Symbol c; - protected Type ctype; - protected Scope locals; - protected Scope statics; - protected JavaTypeFactory make; - protected Signatures sigs; - protected ConstantPool pool; - protected AttributeParser attrib; - - - public ClassfileParser(Global global, AbstractFileReader in, Symbol c) { + protected final Global global; + protected final AbstractFileReader in; + protected final Symbol c; + protected final Type ctype; + protected final JavaTypeFactory make; + protected final ConstantPool pool; + protected final AttributeParser attrib; + protected final Scope locals; + protected final Scope statics; + + + private ClassfileParser(Global global, AbstractFileReader in, Symbol c, JavaTypeFactory make, ConstantPool pool) { this.global = global; this.in = in; this.c = c; - this.make = new JavaTypeCreator(global.definitions); this.ctype = make.classType(c); - this.sigs = new Signatures(global, make); - this.pool = new ConstantPool(in, sigs); + this.make = make; + this.pool = pool; this.attrib = new AttributeParser(in, pool, this); + this.locals = new Scope(); + this.statics = new Scope(); } /** parse the classfile and throw IO exception if there is an * error in the classfile structure */ - public void parse() throws IOException { + public static void parse(Global global, AbstractFileReader in, Symbol c) throws IOException { try { int magic = in.nextInt(); if (magic != JAVA_MAGIC) @@ -84,20 +84,29 @@ public class ClassfileParser implements ClassfileConstants { + majorVersion + "." + minorVersion + ", should be less than " + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION); - pool.indexPool(); + JavaTypeFactory make = new JavaTypeCreator(global.definitions); + Signatures sigs = new Signatures(global, make, in); + ConstantPool pool = new ConstantPool(in, sigs); int flags = in.nextChar(); - Name name = readClassName(in.nextChar()); - if (c != global.definitions.getClass(name)) + Symbol clasz = pool.getClass(in.nextChar()); + if (c != clasz) throw new IOException("class file '" + in.path + "' " - + "contains wrong class " + name); + + "contains wrong class " + clasz.staticType()); + new ClassfileParser(global, in, c, make, pool).parse(flags); + } catch (RuntimeException e) { + if (global.debug) e.printStackTrace(); + throw new IOException("class file '" + in.path + "' is broken"); + } + } + + protected void parse(int flags) { + { // todo: correct flag transition c.flags = transFlags(flags); if ((c.flags & Modifiers.DEFERRED) != 0) c.flags = c.flags & ~Modifiers.DEFERRED | Modifiers.ABSTRACT; Type supertpe = readClassType(in.nextChar()); Type[] basetpes = new Type[in.nextChar() + 1]; - this.locals = new Scope(); - this.statics = new Scope(); // set info of class Type classInfo = Type.compoundType(basetpes, locals, c); c.setInfo(classInfo); @@ -129,9 +138,6 @@ public class ClassfileParser implements ClassfileConstants { //System.out.println("statics class: " + staticsClass); //System.out.println("module: " + c.module()); //System.out.println("modules class: " + c.module().type().symbol()); - } catch (RuntimeException e) { - if (global.debug) e.printStackTrace(); - throw new IOException("class file '" + in.path + "' is broken"); } } @@ -156,37 +162,18 @@ public class ClassfileParser implements ClassfileConstants { return res | Modifiers.JAVA; } - /** read a class name - */ - protected Name readClassName(int i) { - return (Name)pool.readPool(i); - } - /** read a class name and return the corresponding class type */ protected Type readClassType(int i) { - if (i == 0) - return make.anyType(); - Type res = make.classType((Name)pool.readPool(i)); - if (res == Type.ErrorType) - global.error("unknown class reference " + pool.readPool(i)); - return res; - } - - /** read a signature and return it as a type - */ - protected Type readType(int i) { - Name sig = pool.readExternal(i); - byte[] ascii = SourceRepresentation.string2ascii(sig.toString()); - return sigs.sigToType(ascii, 0, ascii.length); + return i == 0 ? make.anyType() : make.classType(pool.getClass(i)); } /** read a field */ protected void parseField() { int flags = in.nextChar(); - Name name = (Name)pool.readPool(in.nextChar()); - Type type = readType(in.nextChar()); + Name name = pool.getName(in.nextChar()); + Type type = pool.getFieldType(in.nextChar()); int mods = transFlags(flags); if ((flags & JAVA_ACC_FINAL) == 0) mods |= Modifiers.MUTABLE; @@ -206,8 +193,8 @@ public class ClassfileParser implements ClassfileConstants { int sflags = transFlags(flags); if ((flags & JAVA_ACC_BRIDGE) != 0) sflags |= Modifiers.BRIDGE; - Name name = (Name)pool.readPool(in.nextChar()); - Type type = readType(in.nextChar()); + Name name = pool.getName(in.nextChar()); + Type type = pool.getMethodType(in.nextChar()); if (CONSTR_N.equals(name)) { Symbol s = c.newConstructor(Position.NOPOS, sflags); // kick out package visible or private constructors @@ -232,6 +219,7 @@ public class ClassfileParser implements ClassfileConstants { setParamOwners(type, constr); constr.setInfo(type); attrib.readAttributes(constr, type, METH_ATTR); + //System.out.println(c + " " + c.allConstructors() + ":" + c.allConstructors().info());//debug //System.out.println("-- enter " + s); } else { diff --git a/sources/scalac/symtab/classfile/ConstantPool.java b/sources/scalac/symtab/classfile/ConstantPool.java index 8d80446342..09108d950a 100644 --- a/sources/scalac/symtab/classfile/ConstantPool.java +++ b/sources/scalac/symtab/classfile/ConstantPool.java @@ -2,184 +2,216 @@ ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** ** /_____/\____/\___/\____/____/ ** -** ** -** $Id$ \* */ +// $Id$ + package scalac.symtab.classfile; -import scalac.*; -import scalac.symtab.*; -import scalac.util.*; +import scalac.atree.AConstant; +import scalac.symtab.Symbol; +import scalac.symtab.Type; +import scalac.util.AbstractFileReader; +import scalac.util.Debug; +import scalac.util.Name; +import scalac.util.SourceRepresentation; +/** This class implements the parsing of class file constant pools. */ public class ConstantPool implements ClassfileConstants { - AbstractFileReader in; - Signatures sigparser; + //######################################################################## + // Private Fields - /** the objects of the constant pool - */ - protected Object[] poolObj; + /** The input file */ + private final AbstractFileReader in; - /** for every constant pool entry, an index into in.buf where the - * defining section of the entry is found - */ - protected int[] poolIdx; + /** The signature parser */ + private final Signatures parser; - /** 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)); - } - } - } + /** The start addresses of all constants */ + private final int[] starts; + + /** The values of the constants (or null if not yet read) */ + private final Object[] values; - /** 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.charAt(0) == '[') || (name.charAt(name.length() - 1) == ';')) { - byte[] ascii = SourceRepresentation.string2ascii(name.toString()); - 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)) { + //######################################################################## + // Public Constructors + + /** Initializes this instance by reading constant pool in file. */ + public ConstantPool(AbstractFileReader in, Signatures parser) { + this.in = in; + this.parser = parser; + this.starts = new int[in.nextChar()]; + this.values = new Object[starts.length]; + for (int index = 1; index < starts.length; ) { + starts[index++] = in.bp; + switch (in.nextByte()) { 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"); + in.skip(in.nextChar()); + continue; 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_STRING: + in.skip(2); + continue; + case CONSTANT_FIELDREF: 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_INTFMETHODREF: case CONSTANT_NAMEANDTYPE: - poolObj[i] = new NameAndType((Name)readPool(in.getChar(index + 1)), - readExternal(in.getChar(index + 3))); - break; - case CONSTANT_STRING: - poolObj[i] = ((Name)readPool(in.getChar(index + 1))).toString(); - break; case CONSTANT_INTEGER: - poolObj[i] = new Integer(in.getInt(index + 1)); - break; case CONSTANT_FLOAT: - poolObj[i] = new Float(in.getFloat(index + 1)); - break; + in.skip(4); + continue; case CONSTANT_LONG: - poolObj[i] = new Long(in.getLong(index + 1)); - break; case CONSTANT_DOUBLE: - poolObj[i] = new Double(in.getDouble(index + 1)); - break; + in.skip(8); + index++; + continue; 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); + throw errorBadTag(in.bp - 1); } } - 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 Methods + + /** Returns the string at given index. */ + public String getString(int index) { + if (index <= 0 || starts.length <= index) throw errorBadIndex(index); + if (values[index] instanceof String) return (String)values[index]; + if (values[index] instanceof Name) return values[index].toString(); + String value = readString(starts[index]); + values[index] = value; + return value; + } + + /** Returns the name at given index. */ + public Name getName(int index) { + if (index <= 0 || starts.length <= index) throw errorBadIndex(index); + if (values[index] instanceof Name) return (Name)values[index]; + Name value = readName(starts[index]); + values[index] = value; + return value; + } - public NameAndType(Name name, Name sig) { - this.name = name; - this.sig = sig; + /** Returns the class at given index. */ + public Symbol getClass(int index) { + if (index <= 0 || starts.length <= index) throw errorBadIndex(index); + if (values[index] instanceof Symbol) return (Symbol)values[index]; + Symbol value = readClass(starts[index]); + values[index] = value; + return value; + } + + /** Returns the field type at given index. */ + public Type getFieldType(int index) { + if (index <= 0 || starts.length <= index) throw errorBadIndex(index); + if (values[index] instanceof Type) return (Type)values[index]; + Type value = readFieldType(starts[index]); + values[index] = value; + return value; + } + + /** Returns the method type at given index. */ + public Type getMethodType(int index) { + if (index <= 0 || starts.length <= index) throw errorBadIndex(index); + if (values[index] instanceof Type) return clone((Type)values[index]); + Type value = readMethodType(starts[index]); + values[index] = value; + return value; + } + + /** Returns the constant value at given index. */ + public AConstant getConstantValue(int index) { + if (index <= 0 || starts.length <= index) throw errorBadIndex(index); + if (values[index] != null) return (AConstant)values[index]; + AConstant value = readConstantValue(starts[index]); + values[index] = value; + return value; + } + + //######################################################################## + // Private Fields + + /** Reads the string at given address. */ + private String readString(int address) { + if (in.byteAt(address) != CONSTANT_UTF8) throw errorBadTag(address); + return parser.at(address).getSignature(); + } + + /** Reads the name at given address. */ + private Name readName(int address) { + return Name.fromString(readString(address)); + } + + /** Reads the class at given address. */ + private Symbol readClass(int address) { + if (in.byteAt(address) != CONSTANT_CLASS) throw errorBadTag(address); + int index = in.getChar(address + 1); + if (index <= 0 || starts.length <= index) throw errorBadIndex(index); + address = starts[index]; + if (in.byteAt(address) != CONSTANT_UTF8) throw errorBadTag(address); + return parser.at(address).readClassName(); + } + + /** Reads the field type at given address. */ + private Type readFieldType(int address) { + if (in.byteAt(address) != CONSTANT_UTF8) throw errorBadTag(address); + return parser.at(address).readValueType(); + } + + /** Reads the method type at given address. */ + private Type readMethodType(int address) { + if (in.byteAt(address) != CONSTANT_UTF8) throw errorBadTag(address); + return parser.at(address).readMethodType(); + } + + /** Reads the constant value at given address. */ + private AConstant readConstantValue(int address) { + switch (in.byteAt(address)) { + case CONSTANT_STRING: + return AConstant.STRING(getString(in.getChar(address + 1))); + case CONSTANT_INTEGER: + return AConstant.INT(in.getInt(address + 1)); + case CONSTANT_FLOAT: + return AConstant.FLOAT(in.getFloat(address + 1)); + case CONSTANT_LONG: + return AConstant.LONG(in.getLong(address + 1)); + case CONSTANT_DOUBLE: + return AConstant.DOUBLE(in.getDouble(address + 1)); + default: + throw errorBadTag(address); + } + } + + /** Returns the type with all its parameters symbols cloned. */ + private Type clone(Type type) { + switch (type) { + case MethodType(Symbol[] params, Type result): + Symbol[] clones = new Symbol[params.length]; + for (int i = 0; i < clones.length; i++) + clones[i] = params[i].cloneSymbol(Symbol.NONE); + return Type.MethodType(clones, result); + case ErrorType: + return type; + default: + throw Debug.abort("illegal case", type); } } + + /** Throws an exception signaling a bad constant index. */ + private RuntimeException errorBadIndex(int index) { + String error = "bad constant pool index: " + index; + throw new RuntimeException(error); + } + + /** Throws an exception signaling a bad tag at given address. */ + private RuntimeException errorBadTag(int address) { + int tag = in.byteAt(address); + String error = "bad constant pool tag " + tag + " at byte " + address; + throw new RuntimeException(error); + } + + //######################################################################## } diff --git a/sources/scalac/symtab/classfile/JavaTypeCreator.java b/sources/scalac/symtab/classfile/JavaTypeCreator.java index d5128efcb3..01e4bf05ba 100644 --- a/sources/scalac/symtab/classfile/JavaTypeCreator.java +++ b/sources/scalac/symtab/classfile/JavaTypeCreator.java @@ -133,30 +133,8 @@ public class JavaTypeCreator implements JavaTypeFactory { /** return the constant type for the given constant. */ - public Type constantType(Type base, Object value) { - return Type.constantType(constantValue(base, value)); - } - - private AConstant constantValue(Type base, Object value) { - if (base.symbol() == definitions.BOOLEAN_CLASS) - return AConstant.BOOLEAN(((Number)value).intValue() != 0); - if (base.symbol() == definitions.BYTE_CLASS) - return AConstant.BYTE(((Number)value).byteValue()); - if (base.symbol() == definitions.SHORT_CLASS) - return AConstant.SHORT(((Number)value).shortValue()); - if (base.symbol() == definitions.CHAR_CLASS) - return AConstant.CHAR((char)((Number)value).intValue()); - if (base.symbol() == definitions.INT_CLASS) - return AConstant.INT(((Number)value).intValue()); - if (base.symbol() == definitions.LONG_CLASS) - return AConstant.LONG(((Number)value).longValue()); - if (base.symbol() == definitions.FLOAT_CLASS) - return AConstant.FLOAT(((Number)value).floatValue()); - if (base.symbol() == definitions.DOUBLE_CLASS) - return AConstant.DOUBLE(((Number)value).doubleValue()); - if (base.symbol() == definitions.STRING_CLASS) - return AConstant.STRING((String)value); - throw Debug.abort("illegal value", value + " - " + base); + public Type constantType(AConstant value) { + return Type.constantType(value); } /** return the type of a given constant. diff --git a/sources/scalac/symtab/classfile/JavaTypeFactory.java b/sources/scalac/symtab/classfile/JavaTypeFactory.java index 5b89ebf231..62ead89e1d 100644 --- a/sources/scalac/symtab/classfile/JavaTypeFactory.java +++ b/sources/scalac/symtab/classfile/JavaTypeFactory.java @@ -8,6 +8,7 @@ package scalac.symtab.classfile; +import scalac.atree.AConstant; import scalac.symtab.Symbol; import scalac.symtab.Type; import scalac.util.Name; @@ -30,6 +31,5 @@ public interface JavaTypeFactory { Type arrayType(Type elemtpe); Type methodType(Type[] argtpes, Type restpe, Type[] thrown); Type packageType(Name packagename); - Type constantType(Type base, Object value); - Type typeOfValue(Object value); // not in use, shall we remove it? + Type constantType(AConstant value); } diff --git a/sources/scalac/symtab/classfile/Signatures.java b/sources/scalac/symtab/classfile/Signatures.java index 9676882aed..3aad3593d4 100644 --- a/sources/scalac/symtab/classfile/Signatures.java +++ b/sources/scalac/symtab/classfile/Signatures.java @@ -2,121 +2,162 @@ ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** ** /_____/\____/\___/\____/____/ ** -** ** -** $Id$ \* */ +// $Id$ + package scalac.symtab.classfile; -import scalac.*; -import scalac.symtab.*; -import scalac.util.*; -import java.util.*; -import Type.*; +import ch.epfl.lamp.util.Position; +import scalac.Global; +import scalac.symtab.Symbol; +import scalac.symtab.Type; +import scalac.util.AbstractFileReader; +import scalac.util.Name; +import scalac.util.SourceRepresentation; +/** This class implements the parsing of class file signatures. */ public class Signatures { - /** signature constants - */ - Name BYTE_SIG = Name.fromString("B"); - Name SHORT_SIG = Name.fromString("S"); - Name CHAR_SIG = Name.fromString("C"); - Name INT_SIG = Name.fromString("I"); - Name LONG_SIG = Name.fromString("J"); - Name FLOAT_SIG = Name.fromString("F"); - Name DOUBLE_SIG = Name.fromString("D"); - Name BOOLEAN_SIG = Name.fromString("Z"); - Name VOID_SIG = Name.fromString("V"); - Name CLASS_SIG = Name.fromString("L"); - Name ARRAY_SIG = Name.fromString("["); - Name ARGBEGIN_SIG = Name.fromString("("); - Name ARGEND_SIG = Name.fromString(")"); - - Global global; - JavaTypeFactory make; - - - public Signatures(Global global, JavaTypeFactory make) { - this.make = make; + //######################################################################## + // Private Fields + + /** The global environment */ + private final Global global; + + /** The Java type factory */ + private final JavaTypeFactory make; + + /** The input file */ + private final AbstractFileReader in; + + /** The address of the first byte of the current signature */ + private int first; + + /** The address of the last byte of the current signature */ + private int last; + + /** The current address (first <= current <= last) */ + private int current; + + //######################################################################## + // Public Constructors + + /** Initializes this instance. */ + public Signatures(Global global, JavaTypeFactory make, + AbstractFileReader in) + { this.global = global; + this.make = make; + this.in = in; } - /** the type represented by signature[offset..]. + //######################################################################## + // Public Methods + + /** + * Sets the address of the next signature to read. The address + * must point to the first byte of a CONSTANT_Utf8_info. */ - protected byte[] signature; - protected int sigp; - protected int limit; - - public Type sigToType(byte[] sig, int offset, int len) { - signature = sig; - sigp = offset; - limit = offset + len; - return sigToType(); + public Signatures at(int address) { + first = address + 3; + last = first + in.getChar(address + 1) - 1; + current = first; + return this; } - protected Type sigToType() { - switch (signature[sigp]) { - case 'B': - sigp++; - return make.byteType(); - case 'C': - sigp++; - return make.charType(); - case 'D': - sigp++; - return make.doubleType(); - case 'F': - sigp++; - return make.floatType(); - case 'I': - sigp++; - return make.intType(); - case 'J': - sigp++; - return make.longType(); - case 'L': - sigp++; - int start = sigp; - while (signature[sigp] != ';') - sigp++; - return make.classType(Name.fromAscii(signature, start, (sigp++) - start)); - case 'S': - sigp++; - return make.shortType(); - case 'V': - sigp++; - return make.voidType(); - case 'Z': - sigp++; - return make.booleanType(); - case '[': - sigp++; - while (('0' <= signature[sigp]) && (signature[sigp] <= '9')) - sigp++; - return make.arrayType(sigToType()); - case '(': - return make.methodType(sigToTypes(')'), sigToType(), Type.EMPTY_ARRAY); - default: - global.error("bad signature: " + - SourceRepresentation.ascii2string(signature, sigp, 1)); - return Type.ErrorType; + /** Returns the current signature. */ + public String getSignature() { + return SourceRepresentation.ascii2string(in.buf, first, last-first+1); + } + + /** Reads the class signature at current address. */ + public Symbol readClassName() { + Symbol owner = global.definitions.ROOT_CLASS; + int start = current; + for (; current <= last; current++) { + int b = in.byteAt(current); + if (b == ';') break; + if (b != '/') continue; + Name name = Name.fromAscii(in.buf, start, current - start); + Symbol module = owner.members().lookup(name); + if (!module.isModule()) { + Symbol symbol = owner.newModule(Position.NOPOS, 0, name); + symbol.moduleClass().setInfo(Type.ErrorType); + error("could not find module " + symbol.staticType()); + if (module.isNone()) owner.members().enterNoHide(symbol); + module = symbol; + } + owner = module.moduleClass(); + start = current + 1; + } + Name name = Name.fromAscii(in.buf, start, current-start).toTypeName(); + Symbol clasz = owner.members().lookup(name); + if (!clasz.isClass()) { + Symbol symbol = owner.newClass(Position.NOPOS, 0, name); + symbol.setInfo(Type.ErrorType); + symbol.allConstructors().setInfo(Type.ErrorType); + error("could not find class " + symbol.staticType()); + if (clasz.isNone()) owner.members().enterNoHide(symbol); + clasz = symbol; + } + current++; + return clasz; + } + + /** Reads the value type signature at current address. */ + public Type readValueType() { + switch (in.byteAt(current++)) { + case 'V': return make.voidType(); + case 'Z': return make.booleanType(); + case 'B': return make.byteType(); + case 'S': return make.shortType(); + case 'C': return make.charType(); + case 'I': return make.intType(); + case 'J': return make.longType(); + case 'F': return make.floatType(); + case 'D': return make.doubleType(); + case 'L': return make.classType(readClassName()); + case '[': return make.arrayType(readValueType()); + default : return errorBadTypeTag(current - 1); } } - protected Type[] sigToTypes(char terminator) { - sigp++; - return sigToTypes(terminator, 0); + /** Reads the method type signature at current address. */ + public Type readMethodType() { + if (in.byteAt(current++) != '(') return errorBadTypeTag(current - 1); + Type[] parameters = readParamterTypes(0); + Type result = readValueType(); + return make.methodType(parameters, result, Type.EMPTY_ARRAY); } - protected Type[] sigToTypes(char terminator, int i) { - if (signature[sigp] == terminator) { - sigp++; + //######################################################################## + // Private Methods + + /** Reads the parameter types at current address. */ + private Type[] readParamterTypes(int i) { + if (in.byteAt(current) == ')') { + current++; return new Type[i]; } else { - Type t = sigToType(); - Type[] vec = sigToTypes(terminator, i+1); - vec[i] = t; - return vec; + Type type = readValueType(); + Type[] types = readParamterTypes(i + 1); + types[i] = type; + return types; } } + + /** Signals a bad tag at given address. Return ErrorType. */ + private Type errorBadTypeTag(int address) { + char tag = (char)in.byteAt(address); + error("bad tag '" + tag + "' in signature '" + getSignature() + "'"); + return Type.ErrorType; + } + + /** Signals the given error. */ + private void error(String error) { + global.error("class file '" + in.path + "': " + error); + } + + //######################################################################## } -- cgit v1.2.3