diff options
Diffstat (limited to 'sources/scalac/symtab/classfile')
-rw-r--r-- | sources/scalac/symtab/classfile/AttributeParser.java | 439 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/ClassParser.java | 111 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/ClassfileConstants.java | 57 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/ClassfileParser.java | 239 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/ConstantPool.java | 183 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/JavaTypeCreator.java | 82 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/JavaTypeFactory.java | 28 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/PackageParser.java | 129 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/Signatures.java | 122 |
9 files changed, 1390 insertions, 0 deletions
diff --git a/sources/scalac/symtab/classfile/AttributeParser.java b/sources/scalac/symtab/classfile/AttributeParser.java new file mode 100644 index 0000000000..0ed09b44d0 --- /dev/null +++ b/sources/scalac/symtab/classfile/AttributeParser.java @@ -0,0 +1,439 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.*; +import scalac.symtab.*; +import scalac.util.*; +import java.util.*; + +public class AttributeParser implements ClassfileConstants { + + /** the classfile input buffer + */ + protected AbstractFileReader in; + + /** the constant pool + */ + protected ConstantPool pool; + + protected ClassfileParser parser; + + /** constructor + */ + public AttributeParser(AbstractFileReader in, ConstantPool pool, ClassfileParser parser) { + this.in = in; + this.pool = pool; + this.parser = parser; + } + + public int nameToId(Name name) { + if (name == SOURCEFILE_N) + return SOURCEFILE_ATTR; + if (name == SYNTHETIC_N) + return SYNTHETIC_ATTR; + if (name == DEPRECATED_N) + return DEPRECATED_ATTR; + if (name == CODE_N) + return CODE_ATTR; + if (name == EXCEPTIONS_N) + return EXCEPTIONS_ATTR; + if (name == CONSTANT_VALUE_N) + return CONSTANT_VALUE_ATTR; + if (name == LINE_NUM_TABLE_N) + return LINE_NUM_TABLE_ATTR; + if (name == LOCAL_VAR_TABLE_N) + return LOCAL_VAR_TABLE_ATTR; + if (name == INNERCLASSES_N) + return INNERCLASSES_ATTR; + if (name == META_N) + return META_ATTR; + if (name == SCALA_N) + return SCALA_ATTR; + return BAD_ATTR; + } + + 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()); + int attr = nameToId(attrName); + int attrLen = in.nextInt(); + if ((attrs & attr) == 0) { + //System.out.println("# skipping " + attrName + " of " + def); + in.skip(attrLen); + } else { + //System.out.println("# reading " + attrName + " of " + def); + readAttribute(def, type, attr, attrLen); + } + } + return def; + } + + public void readAttribute(Symbol sym, Type type, int attr, int attrLen) { + switch (attr) { + // class attributes + case SCALA_ATTR: + in.skip(attrLen); + /* not yet + Name sourcefile = (Name)pool.readPool(in.nextChar()); + new UnPickle( + (JavaClassSymbol) sym, in.nextBytes(attrLen - 2), sourcefile); + */ + return; + + case SOURCEFILE_ATTR: + // ((ClassDef)def).sourcefile = (Name)reader.readPool(in.nextChar()); + in.skip(attrLen); + return; + + case INNERCLASSES_ATTR: + /* int n = in.nextChar(); + for (int i = 0; i < n; i++) { + Symbol inner = (Symbol)pool.readPool(in.nextChar()); + Symbol outer = (Symbol)pool.readPool(in.nextChar()); + Name name = (Name)pool.readPool(in.nextChar()); + int flags = in.nextChar(); + if (name != null) { + inner.owner(outer); + inner.mangled(name); + inner.flags = flags; + } + } */ + in.skip(attrLen); + return; + + // method attributes + case CODE_ATTR: + in.skip(attrLen); + return; + + case EXCEPTIONS_ATTR: + //int nexceptions = in.nextChar(); + //Type[] thrown = new Type[nexceptions]; + //for (int j = 0; j < nexceptions; j++) + // thrown[j] = make.classType(reader.readClassName(in.nextChar())); + //((MethodType)def.type).thrown = thrown; + in.skip(attrLen); + return; + + case LINE_NUM_TABLE_ATTR: + in.skip(attrLen); + return; + + case LOCAL_VAR_TABLE_ATTR: + in.skip(attrLen); + return; + + // general attributes + case SYNTHETIC_ATTR: + sym.flags |= Modifiers.SYNTHETIC; + return; + + case DEPRECATED_ATTR: + sym.flags |= Modifiers.DEPRECATED; + return; + + case CONSTANT_VALUE_ATTR: + // Type ctype = (Type)reader.readPool(in.nextChar()); + // def.type = types.coerce(ctype, def.type); + in.skip(attrLen); + return; + + case META_ATTR: + //System.out.println("parsing meta data for " + sym); + String meta = pool.readPool(in.nextChar()).toString().trim(); + sym.setInfo(new MetaParser(meta, tvars, sym, type).parse(), parser.phaseId); + + return; + } + throw new RuntimeException("unknown classfile attribute"); + } + + Scope tvars = new Scope(); + + class MetaParser { + + Symbol owner; + StringTokenizer scanner; + Type defaultType; + String token; + Scope tvars; + Scope locals; + + MetaParser(String meta, Scope tvars, Symbol owner, Type defaultType) { + //System.out.println("meta = " + meta); + this.scanner = new StringTokenizer(meta, "()[], \t<;", true); + this.defaultType = defaultType; + this.owner = owner; + this.tvars = tvars; + } + + private Symbol getTVar(String name) { + return getTVar(name, parser.c.constructor()); + } + + private Symbol getTVar(String name, Symbol owner) { + if (name.startsWith("?")) { + if (locals != null) { + Symbol s = locals.lookup(Name.fromString(name).toTypeName()); + if (s != Symbol.NONE) + return s; + } + Symbol s = tvars.lookup(Name.fromString(name).toTypeName()); + if (s == Symbol.NONE) { + s = new TypeSymbol(Kinds.TYPE, + Position.NOPOS, + Name.fromString(token).toTypeName(), + owner, + Modifiers.PARAM); + s.setInfo(parser.defs.ANY_TYPE, parser.phaseId); + tvars.enter(s); + } + return s; + } else + return Symbol.NONE; + } + + private String nextToken() { + do { + token = scanner.nextToken().trim(); + } while (token.length() == 0); + return token; + } + + protected Type parse() { + if (scanner.hasMoreTokens()) { + nextToken(); + if (!scanner.hasMoreTokens()) + return defaultType; + if ("class".equals(token)) + return parseMetaClass(); + if ("method".equals(token)) + return parseMetaMethod(); + if ("field".equals(token)) + return parseMetaField(); + if ("constr".equals(token)) + return parseConstrField(); + } + return defaultType; + } + + protected Type parseMetaClass() { + nextToken(); + //System.out.println("parse meta class " + token);//DEBUG + if ("[".equals(token)) { + try { + Vector syms = new Vector(); + do { + nextToken(); + assert token.startsWith("?"); + Symbol s = getTVar(token); + if (s == Symbol.NONE) + return defaultType; + nextToken(); + //System.out.println("new var " + s + ", " + token);//DEBUG + if (token.equals("<")) { + nextToken(); + s.setInfo(parseType(), parser.phaseId); + } + syms.add(s); + } while (token.equals(",")); + assert "]".equals(token); + nextToken(); + Symbol[] smbls = (Symbol[])syms.toArray(new Symbol[syms.size()]); + //System.out.println("*** " + syms);//DEBUG + Type constrtype = Type.appliedType( + parser.ctype, Symbol.type(smbls)); + + if ((parser.c.flags & Modifiers.INTERFACE) != 0) { + parser.c.constructor().setInfo( + Type.PolyType(smbls, constrtype), parser.phaseId); + //System.out.println("info = " + parser.c.constructor().info());//DEBUG + } + Symbol[] constrs; + switch (parser.c.constructor().rawInfo()) { + case OverloadedType(Symbol[] alts, _): + constrs = alts; + break; + default: + constrs = new Symbol[]{parser.c.constructor()}; + } + for (int i = 0; i < constrs.length; i++) { + //System.out.println("info = " + e.sym.info()); + switch (constrs[i].rawInfo()) { + case MethodType(Symbol[] vparams, _): + constrs[i].setInfo( + Type.PolyType(smbls, + Type.MethodType( + vparams, constrtype)), parser.phaseId); + break; + case PolyType(_, _): + constrs[i].setInfo( + Type.PolyType(smbls, constrtype), parser.phaseId); + break; + } + //System.out.println("*** constructor " + e.sym + ": " + e.sym.info());//DEBUG + } + } catch (NoSuchElementException e) { + } + } + Type res = defaultType; + if ("extends".equals(token)) { + Vector basetpes = new Vector(); + do { + nextToken(); + basetpes.add(parseType()); + } while (token.equals("with")); + switch (defaultType) { + case CompoundType(_, Scope scope): + res = Type.compoundType( + (Type[])basetpes.toArray(new Type[basetpes.size()]), + scope, + defaultType.symbol()); + } + } + assert ";".equals(token); + return res; + } + + protected Type parseType() { + String name = token; + Symbol s = getTVar(name); + nextToken(); + if (s != Symbol.NONE) + return s.type(); + Symbol clazz = parser.defs.getClass(Name.fromString(name)); + if (token.equals("[")) { + Vector types = new Vector(); + do { + nextToken(); + types.add(parseType()); + } while (token.equals(",")); + assert "]".equals(token); + nextToken(); + Type[] args = new Type[types.size()]; + types.toArray(args); + return Type.TypeRef(clazz.owner().thisType(), clazz, args); + } else { + return parser.defs.monoType(clazz); + } + } + + protected Type parseMetaMethod() { + locals = new Scope(); + try { + nextToken(); + Symbol[] smbls = null; + //System.out.println("parse meta method " + token); + if ("[".equals(token)) { + Vector syms = new Vector(); + do { + nextToken(); + if ("]".equals(token)) + break; + assert token.startsWith("?"); + Symbol s = getTVar(token, owner); + if (s == Symbol.NONE) + return defaultType; + nextToken(); + //System.out.println("new var " + s + ", " + token); + if (token.equals("<")) { + nextToken(); + s.setInfo(parseType(), parser.phaseId); + } + syms.add(s); + } while (token.equals(",")); + assert "]".equals(token); + nextToken(); + smbls = (Symbol[])syms.toArray(new Symbol[syms.size()]); + } + if ("(".equals(token)) { + int i = 0; + Vector params = new Vector(); + do { + nextToken(); + if (")".equals(token)) + break; + params.add(new TermSymbol( + Position.NOPOS, + Name.fromString("x" + (i++)), + owner, + Modifiers.PARAM).setInfo(parseType(), parser.phaseId)); + //System.out.println(" + " + token); + } while (token.equals(",")); + assert ")".equals(token); + nextToken(); + //System.out.println("+++ method " + token); + Type restpe = parseType(); + assert ";".equals(token); + if (smbls == null) + return Type.MethodType( + (Symbol[])params.toArray(new Symbol[params.size()]), + restpe); + else + return Type.PolyType( + smbls, + Type.MethodType( + (Symbol[])params.toArray(new Symbol[params.size()]), + restpe)); + } else { + Type res = parseType(); + assert ";".equals(token); + if (smbls == null) + return Type.PolyType(Symbol.EMPTY_ARRAY, res); + else + return Type.PolyType(smbls, res); + } + } catch (NoSuchElementException e) { + return defaultType; + } finally { + locals = null; + } + } + + protected Type parseMetaField() { + nextToken(); + return parseType(); + } + + protected Type parseConstrField() { + try { + nextToken(); + //System.out.println("+++ constr " + token); + if ("(".equals(token)) { + int i = 0; + Vector params = new Vector(); + do { + nextToken(); + if (")".equals(token)) + break; + params.add(new TermSymbol( + Position.NOPOS, + Name.fromString("x" + (i++)), + owner, + Modifiers.PARAM).setInfo(parseType(), parser.phaseId)); + //System.out.println(" + " + token); + } while (token.equals(",")); + assert ")".equals(token); + nextToken(); + assert ";".equals(token); + return Type.MethodType( + (Symbol[])params.toArray(new Symbol[params.size()]), + parser.ctype); + } else { + assert ";".equals(token); + return Type.PolyType(Symbol.EMPTY_ARRAY, parser.ctype); + } + } catch (NoSuchElementException e) { + return defaultType; + } + } + } +} diff --git a/sources/scalac/symtab/classfile/ClassParser.java b/sources/scalac/symtab/classfile/ClassParser.java new file mode 100644 index 0000000000..9948ba33cf --- /dev/null +++ b/sources/scalac/symtab/classfile/ClassParser.java @@ -0,0 +1,111 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.*; +import scalac.symtab.*; +import scalac.util.*; +import java.io.*; + + +public class ClassParser extends Type.LazyType { + + /** the global compilation environment + */ + protected Global global; + + public ClassParser(Global global) { + this.global = global; + } + + /** complete class symbol c by loading the class + */ + public void complete(Symbol c) { + //System.out.println("loading " + c);//DEBUG + try { + long msec = System.currentTimeMillis(); + String filename = externalizeFileName(c.fullName()) + ".class"; + AbstractFile f = global.classPath.openFile(filename); + if (f == null) + global.error("could not read class " + c); + else { + new ClassfileParser(global, new AbstractFileReader(f), c).parse(); + global.operation("loaded " + f.getPath() + " in " + + (System.currentTimeMillis() - msec) + "ms"); + //for (Definition e = c.locals().elems; e != null; e = e.sibling) + // if (e.def.kind == TYP) + // e.def.complete(); + } + } catch (IOException e) { + e.printStackTrace(); + global.error("i/o error while loading " + c); + c.setInfo(Type.ErrorType); + } + } + + /** return external representation of file name s, + * converting '.' to File.separatorChar + */ + public String externalizeFileName(Name n) { + if ((n == null) || (n.length() == 0)) + return "."; + byte[] ascii = n.toAscii(); + String s = SourceRepresentation.ascii2string( + ascii, 0, ascii.length); + return s.replace('.', File.separatorChar); + } + + public Type.LazyType staticsParser(Symbol clazz) { + return new StaticsParser(clazz); + } + + public Type.LazyType aliasParser(Symbol alias) { + return new AliasParser(alias); + } + + class StaticsParser extends Type.LazyType { + Symbol clazz; + + StaticsParser(Symbol clazz) { + this.clazz = clazz; + } + + public void complete(Symbol statics) { + ClassParser.this.complete(clazz); + } + } + + class AliasParser extends Type.LazyType { + Symbol alias; + + AliasParser(Symbol alias) { + this.alias = alias; + } + + public void complete(Symbol c) { + try { + long msec = System.currentTimeMillis(); + String filename = externalizeFileName(alias.fullName()) + ".class"; + AbstractFile f = global.classPath.openFile(filename); + if (f == null) + global.error("could not read class " + c); + else { + new ClassfileParser(global, new AbstractFileReader(f), c).parse(); + global.operation("loaded " + f.getPath() + " in " + + (System.currentTimeMillis() - msec) + "ms"); + } + } catch (IOException e) { + e.printStackTrace(); + global.error("i/o error while loading " + c); + c.setInfo(Type.ErrorType); + } + } + } +} + diff --git a/sources/scalac/symtab/classfile/ClassfileConstants.java b/sources/scalac/symtab/classfile/ClassfileConstants.java new file mode 100644 index 0000000000..16b9f5af44 --- /dev/null +++ b/sources/scalac/symtab/classfile/ClassfileConstants.java @@ -0,0 +1,57 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.util.Name; + +public interface ClassfileConstants { + + int JAVA_MAGIC = 0xCAFEBABE; + int JAVA_MAJOR_VERSION = 45; + int JAVA_MINOR_VERSION = 3; + + int CONSTANT_UTF8 = 1; + int CONSTANT_UNICODE = 2; + int CONSTANT_INTEGER = 3; + int CONSTANT_FLOAT = 4; + int CONSTANT_LONG = 5; + int CONSTANT_DOUBLE = 6; + int CONSTANT_CLASS = 7; + int CONSTANT_STRING = 8; + int CONSTANT_FIELDREF = 9; + int CONSTANT_METHODREF = 10; + int CONSTANT_INTFMETHODREF = 11; + int CONSTANT_NAMEANDTYPE = 12; + + int BAD_ATTR = 0x00000; + int SOURCEFILE_ATTR = 0x00001; + int SYNTHETIC_ATTR = 0x00002; + int DEPRECATED_ATTR = 0x00004; + int CODE_ATTR = 0x00008; + int EXCEPTIONS_ATTR = 0x00010; + int CONSTANT_VALUE_ATTR = 0x00020; + int LINE_NUM_TABLE_ATTR = 0x00040; + int LOCAL_VAR_TABLE_ATTR = 0x00080; + int INNERCLASSES_ATTR = 0x08000; + int META_ATTR = 0x10000; + int SCALA_ATTR = 0x20000; + + Name SOURCEFILE_N = Name.fromString("SourceFile"); + Name SYNTHETIC_N = Name.fromString("Synthetic"); + Name DEPRECATED_N = Name.fromString("Deprecated"); + Name CODE_N = Name.fromString("Code"); + Name EXCEPTIONS_N = Name.fromString("Exceptions"); + Name CONSTANT_VALUE_N = Name.fromString("ConstantValue"); + Name LINE_NUM_TABLE_N = Name.fromString("LineNumberTable"); + Name LOCAL_VAR_TABLE_N = Name.fromString("LocalVariableTable"); + Name INNERCLASSES_N = Name.fromString("InnerClasses"); + Name META_N = Name.fromString("JacoMeta"); + Name SCALA_N = Name.fromString("ScalaSignature"); + Name CONSTR_N = Name.fromString("<init>"); +} diff --git a/sources/scalac/symtab/classfile/ClassfileParser.java b/sources/scalac/symtab/classfile/ClassfileParser.java new file mode 100644 index 0000000000..956c83968f --- /dev/null +++ b/sources/scalac/symtab/classfile/ClassfileParser.java @@ -0,0 +1,239 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.*; +import scalac.util.*; +import scalac.symtab.*; +import java.io.*; +import java.util.*; + +//todo: don't keep statics module in scope. + +public class ClassfileParser implements ClassfileConstants { + + static final int CLASS_ATTR = SOURCEFILE_ATTR + | INNERCLASSES_ATTR + | SYNTHETIC_ATTR + | DEPRECATED_ATTR + | META_ATTR + | SCALA_ATTR; + static final int METH_ATTR = CODE_ATTR + | EXCEPTIONS_ATTR + | SYNTHETIC_ATTR + | DEPRECATED_ATTR + | META_ATTR; + static final int FIELD_ATTR = CONSTANT_VALUE_ATTR + | SYNTHETIC_ATTR + | DEPRECATED_ATTR + | META_ATTR; + + protected Global global; + protected AbstractFileReader in; + protected Symbol c; + protected Type ctype; + protected Scope locals; + protected Scope statics; + protected Scope constr; + protected JavaTypeFactory make; + protected Signatures sigs; + protected ConstantPool pool; + protected AttributeParser attrib; + protected Definitions defs; + protected int phaseId; + + + public ClassfileParser(Global global, AbstractFileReader in, Symbol c) { + this.global = global; + this.in = in; + this.c = c; + this.ctype = Type.TypeRef(c.owner().thisType(), c, Type.EMPTY_ARRAY); + this.make = new JavaTypeCreator(global); + this.sigs = new Signatures(global, make); + this.pool = new ConstantPool(in, sigs); + this.attrib = new AttributeParser(in, pool, this); + this.defs = global.definitions; + this.phaseId = global.POST_ANALYZER_PHASE_ID; + } + + + /** parse the classfile and throw IO exception if there is an + * error in the classfile structure + */ + public void parse() throws IOException { + try { + if (in.nextInt() != JAVA_MAGIC) + throw new IOException("illegal start of class file"); + int minorVersion = in.nextChar(); + int majorVersion = in.nextChar(); + if ((majorVersion < JAVA_MAJOR_VERSION) || + ((majorVersion == JAVA_MAJOR_VERSION) && + (minorVersion < JAVA_MINOR_VERSION))) + throw new IOException("class file has wrong version " + + majorVersion + "." + minorVersion + ", should be " + + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION); + pool.indexPool(); + int flags = in.nextChar(); + Name name = readClassName(in.nextChar()); + if (c.fullName() != name) + throw new IOException("class file '" + c.fullName() + + "' contains wrong class " + name); + // todo: correct flag transition + c.flags = transFlags(flags); + if ((c.flags & Modifiers.ABSTRACT) != 0) + c.flags = c.flags & ~Modifiers.ABSTRACT | Modifiers.ABSTRACTCLASS; + Type supertpe = readClassType(in.nextChar()); + Type[] basetpes = new Type[in.nextChar() + 1]; + this.locals = new Scope(); + this.statics = new Scope(); + this.constr = new Scope(); + // set type of class + Type classType = Type.compoundType(basetpes, locals, c); + c.setInfo(classType, phaseId); + // set type of statics + Symbol staticsClass = c.module().moduleClass(); + Type staticsInfo = Type.compoundType(Type.EMPTY_ARRAY, statics, staticsClass); + staticsClass.setInfo(staticsInfo, phaseId); + c.module().setInfo(Type.TypeRef(staticsClass.owner().thisType(), + staticsClass, Type.EMPTY_ARRAY)); + basetpes[0] = supertpe; + for (int i = 1; i < basetpes.length; i++) + basetpes[i] = readClassType(in.nextChar()); + int fieldCount = in.nextChar(); + for (int i = 0; i < fieldCount; i++) + parseField(); + int methodCount = in.nextChar(); + for (int i = 0; i < methodCount; i++) + parseMethod(); + // set constructor type to the declared type + Symbol[] constrs = constr.elements(); + if (constrs.length != 0) { + assert constrs.length == 1; + c.constructor().setInfo(constrs[0].info(), phaseId); + } else { + Type constrtype = ((c.flags & Modifiers.INTERFACE) != 0) + ? Type.PolyType(Symbol.EMPTY_ARRAY, ctype) + : Type.MethodType(new Symbol[]{Symbol.NONE}, ctype); + c.constructor().setInfo(constrtype, phaseId); + } + attrib.readAttributes(c, classType, CLASS_ATTR); + //System.out.println("dynamic class: " + c); + //System.out.println("statics class: " + staticsClass); + //System.out.println("module: " + c.module()); + //System.out.println("modules class: " + c.module().type().symbol()); + } catch (RuntimeException e) { + e.printStackTrace(); + throw new IOException("bad class file (" + e.getMessage() + ")"); + } + } + + /** convert Java modifiers into Scala flags + */ + public int transFlags(int flags) { + int res = 0; + if (((flags & 0x0007) == 0) || + ((flags & 0x0002) != 0)) + res |= Modifiers.PRIVATE; + else if ((flags & 0x0004) != 0) + res |= Modifiers.PROTECTED; + if ((flags & 0x0400) != 0) + res |= Modifiers.ABSTRACT; + if ((flags & 0x0010) != 0) + res |= Modifiers.FINAL; + if ((flags & 0x0200) != 0) + res |= Modifiers.INTERFACE | Modifiers.ABSTRACTCLASS; + 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 defs.ANY_TYPE; + Type res = defs.getJavaType((Name)pool.readPool(i)); + if (res == Type.ErrorType) + global.error("unknown class reference " + pool.readPool(i)); + if (res.symbol() == defs.JAVA_OBJECT_TYPE.symbol()) + return defs.ANYREF_TYPE; + else + return res; + } + + /** read a signature and return it as a type + */ + protected Type readType(int i) { + Name sig = pool.readExternal(i); + return sigs.sigToType(Name.names, sig.index, sig.length()); + } + + /** read a field + */ + protected void parseField() { + int flags = in.nextChar(); + Name name = (Name)pool.readPool(in.nextChar()); + Type type = readType(in.nextChar()); + int mods = transFlags(flags); + if ((flags & 0x0010) == 0) + mods |= Modifiers.MUTABLE; + Symbol owner = c; + if ((flags & 0x0008) != 0) + owner = c.module().moduleClass(); + Symbol s = new TermSymbol(Position.NOPOS, name, owner, mods); + s.setInfo(type, phaseId); + attrib.readAttributes(s, type, FIELD_ATTR); + ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s); + } + + /** read a method + */ + protected void parseMethod() { + int flags = in.nextChar(); + Name name = (Name)pool.readPool(in.nextChar()); + Type type = readType(in.nextChar()); + if (CONSTR_N.equals(name)) { + Symbol s = TermSymbol.newConstructor(c, transFlags(flags)); + // kick out protected, package visible or + // private constructors + if (((flags & 0x0004) != 0) || + ((flags & 0x0002) != 0) || + ((flags & 0x0007) == 0)) { + attrib.readAttributes(s, type, METH_ATTR); + return; + } + switch (type) { + case MethodType(Symbol[] vparams, _): + if (c == defs.OBJECT_CLASS) + type = Type.PolyType(Symbol.EMPTY_ARRAY, ctype); + else + type = Type.MethodType(vparams, ctype); + break; + default: + throw new ApplicationError(); + } + s.setInfo(type, phaseId); + attrib.readAttributes(s, type, METH_ATTR); + //System.out.println("-- enter " + s); + constr.enterOrOverload(s); + } else { + Symbol s = new TermSymbol( + Position.NOPOS, name, + ((flags & 0x0008) != 0) ? c.module().moduleClass() : c, + transFlags(flags)); + s.setInfo(type, phaseId); + attrib.readAttributes(s, type, METH_ATTR); + ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s); + } + } +} 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; + } + } +} diff --git a/sources/scalac/symtab/classfile/JavaTypeCreator.java b/sources/scalac/symtab/classfile/JavaTypeCreator.java new file mode 100644 index 0000000000..5bdc9402ba --- /dev/null +++ b/sources/scalac/symtab/classfile/JavaTypeCreator.java @@ -0,0 +1,82 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.Global; +import scalac.util.*; +import scalac.symtab.*; +import Type.*; + + +public class JavaTypeCreator implements JavaTypeFactory { + + protected Global global; + + public JavaTypeCreator(Global global) { + this.global = global; + } + + public Type byteType() { + return global.definitions.BYTE_TYPE; + } + + public Type shortType() { + return global.definitions.SHORT_TYPE; + } + + public Type charType() { + return global.definitions.CHAR_TYPE; + } + + public Type intType() { + return global.definitions.INT_TYPE; + } + + public Type longType() { + return global.definitions.LONG_TYPE; + } + + public Type floatType() { + return global.definitions.FLOAT_TYPE; + } + + public Type doubleType() { + return global.definitions.DOUBLE_TYPE; + } + + public Type booleanType() { + return global.definitions.BOOLEAN_TYPE; + } + + public Type voidType() { + return global.definitions.UNIT_TYPE; + } + + public Type classType(Name classname) { + return global.definitions.getJavaType(classname); + } + + public Type arrayType(Type elemtpe) { + return global.definitions.arrayType(elemtpe); + } + + public Type methodType(Type[] argtpes, Type restpe, Type[] thrown) { + Symbol[] args = new Symbol[argtpes.length]; + for (int i = 0; i < args.length; i++) { + args[i] = new TermSymbol( + Position.NOPOS, Name.fromString("x" + i), Symbol.NONE, Modifiers.PARAM); + args[i].setInfo(argtpes[i]); + } + return new MethodType(args, restpe); + } + + public Type packageType(Name packagename) { + return null; + } +} diff --git a/sources/scalac/symtab/classfile/JavaTypeFactory.java b/sources/scalac/symtab/classfile/JavaTypeFactory.java new file mode 100644 index 0000000000..8205055bc9 --- /dev/null +++ b/sources/scalac/symtab/classfile/JavaTypeFactory.java @@ -0,0 +1,28 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.symtab.Type; +import scalac.util.Name; + +public interface JavaTypeFactory { + Type byteType(); + Type shortType(); + Type charType(); + Type intType(); + Type longType(); + Type floatType(); + Type doubleType(); + Type booleanType(); + Type voidType(); + Type classType(Name classname); + Type arrayType(Type elemtpe); + Type methodType(Type[] argtpes, Type restpe, Type[] thrown); + Type packageType(Name packagename); +} diff --git a/sources/scalac/symtab/classfile/PackageParser.java b/sources/scalac/symtab/classfile/PackageParser.java new file mode 100644 index 0000000000..50fcb46b00 --- /dev/null +++ b/sources/scalac/symtab/classfile/PackageParser.java @@ -0,0 +1,129 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.*; +import scalac.symtab.*; +import scalac.util.*; +import java.io.*; + +public class PackageParser extends Type.LazyType { + + /** the global compilation environment + */ + protected Global global; + + /** the class parser + */ + public ClassParser classCompletion; + + public PackageParser(Global global) { + this.global = global; + this.classCompletion = new ClassParser(global); + } + + /** complete package type symbol p by loading all package members + */ + public void complete(Symbol p) { + long msec = System.currentTimeMillis(); + Scope members = new Scope(); + String dirname = null; + Name name = p.fullName(); + if (name.length() == 0) { + // includeMembers(AbstractFile.open(null, "."), p, members, false); + } else { + dirname = externalizeFileName(name); + assert !dirname.startsWith("com") : p;//debug + if (!dirname.endsWith("/")) + dirname += "/"; + } + String[] base = global.classPath.components(); + for (int i = 0; i < base.length; i++) { + includeMembers( + AbstractFile.open(base[i], dirname), p, members, dirname != null); + } + p.setInfo(Type.compoundType(Type.EMPTY_ARRAY, members, p)); + if (dirname == null) + dirname = "anonymous package"; + global.operation("scanned " + dirname + " in " + + (System.currentTimeMillis() - msec) + "ms"); + } + + /** read directory of a classpath directory and include members + * in package/module scope + */ + protected void includeMembers(AbstractFile dir, Symbol p, Scope locals, + boolean inclClasses) { + if (dir == null) + return; + String[] filenames = null; + try { + if ((filenames = dir.list()) == null) + return; + for (int j = 0; j < filenames.length; j++) { + String fname = filenames[j]; + if (inclClasses && fname.endsWith(".class")) { + Name n = Name.fromString(fname.substring(0, fname.length() - 6)) + .toTypeName(); + ClassSymbol clazz = new ClassSymbol(n, p, classCompletion); + clazz.constructor().setInfo( + classCompletion.staticsParser(clazz)); + // enter class + locals.enter(clazz); + locals.enter(clazz.constructor()); + // enter module, except for scala.Object class + // todo: why not there also?. + if (!(n == Names.Object.toTypeName() && + p.fullName().toTermName() == Names.scala)) { + Scope.Entry e = locals.lookupEntry(clazz.module().name); + if (e != Scope.Entry.NONE) { + // we already have a package of the same name; delete it + locals.unlink(e); + } + locals.enter(clazz.module()); + } + } else if (fname.endsWith("/") && !fname.equals("META-INF/")) { + Name n = Name.fromString(fname.substring(0, fname.length() - 1)); + if (locals.lookup(n) == Symbol.NONE) { + TermSymbol module = TermSymbol.newJavaPackageModule(n, p, this); + locals.enter(module); + } + } else if (fname.endsWith(".scala")) { + Name n = Name.fromString(fname.substring(0, fname.length() - 6)) + .toTypeName(); + if (locals.lookup(n) == Symbol.NONE) { + SourceCompleter completer = new SourceCompleter(global, + dir.getPath() + File.separatorChar + fname); + ClassSymbol clazz = new ClassSymbol(n, p, completer); + clazz.constructor().setInfo(completer); + clazz.module().setInfo(completer); + // enter class + locals.enter(clazz); + locals.enter(clazz.constructor()); + locals.enter(clazz.module()); + } + } + } + } catch (IOException e) { + } + } + + /** return external representation of file name s, + * converting '.' to File.separatorChar + */ + + public String externalizeFileName(Name n) { + if ((n == null) || (n.length() == 0)) + return "."; + byte[] ascii = n.toAscii(); + String s = SourceRepresentation.ascii2string( + ascii, 0, ascii.length); + return s.replace('.', File.separatorChar); + } +} diff --git a/sources/scalac/symtab/classfile/Signatures.java b/sources/scalac/symtab/classfile/Signatures.java new file mode 100644 index 0000000000..9676882aed --- /dev/null +++ b/sources/scalac/symtab/classfile/Signatures.java @@ -0,0 +1,122 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab.classfile; + +import scalac.*; +import scalac.symtab.*; +import scalac.util.*; +import java.util.*; +import Type.*; + +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; + this.global = global; + } + + /** the type represented by signature[offset..]. + */ + 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(); + } + + 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; + } + } + + protected Type[] sigToTypes(char terminator) { + sigp++; + return sigToTypes(terminator, 0); + } + + protected Type[] sigToTypes(char terminator, int i) { + if (signature[sigp] == terminator) { + sigp++; + return new Type[i]; + } else { + Type t = sigToType(); + Type[] vec = sigToTypes(terminator, i+1); + vec[i] = t; + return vec; + } + } +} |