diff options
author | Paul Phillips <paulp@improving.org> | 2010-02-04 13:33:06 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-02-04 13:33:06 +0000 |
commit | a1a6ab90ac5fe7d5db2f6fba788ce14c1613d9c6 (patch) | |
tree | a70c578ce72906368a8e733ac8aff914ae8cbf42 | |
parent | 9ee1f2f3b8ed91897bb298592f8a600ff5e4622d (diff) | |
download | scala-a1a6ab90ac5fe7d5db2f6fba788ce14c1613d9c6.tar.gz scala-a1a6ab90ac5fe7d5db2f6fba788ce14c1613d9c6.tar.bz2 scala-a1a6ab90ac5fe7d5db2f6fba788ce14c1613d9c6.zip |
The remainder of isolating MSIL from the rest o...
The remainder of isolating MSIL from the rest of the classpath code. To
accomplish this I made ClassRep an inner class of ClassPath (which given
the broad definition of ClassPath already in place, it conceptually is
already) and as a bonus this allowed dropping its type parameter. Review
by rytz.
6 files changed, 211 insertions, 195 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 23e525d8c8..a3751f0c48 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -14,7 +14,7 @@ import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute} import scala.collection.mutable.{HashMap, HashSet} import scala.compat.Platform.currentTime import scala.tools.nsc.io.AbstractFile -import scala.tools.nsc.util.{ClassPath, ClassRep, JavaClassPath, MsilClassPath} +import scala.tools.nsc.util.{ ClassPath, JavaClassPath } import classfile.ClassfileParser import Flags._ @@ -136,7 +136,7 @@ abstract class SymbolLoaders { * (anonymous classes, implementation classes, module classes), their * symtab is encoded in the pickle of another class. */ - protected def doLoad(cls: ClassRep[T]): Boolean + protected def doLoad(cls: classpath.AnyClassRep): Boolean protected def newClassLoader(bin: T): SymbolLoader @@ -197,12 +197,11 @@ abstract class SymbolLoaders { } } - class JavaPackageLoader(classpath: ClassPath[AbstractFile]) extends PackageLoader(classpath) { protected def needCompile(bin: AbstractFile, src: AbstractFile) = (src.lastModified >= bin.lastModified) - protected def doLoad(cls: ClassRep[AbstractFile]) = true + protected def doLoad(cls: classpath.AnyClassRep) = true protected def newClassLoader(bin: AbstractFile) = new ClassfileLoader(bin) @@ -215,7 +214,7 @@ abstract class SymbolLoaders { protected def needCompile(bin: MSILType, src: AbstractFile) = false // always use compiled file on .net - protected def doLoad(cls: ClassRep[MSILType]) = { + protected def doLoad(cls: classpath.AnyClassRep) = { if (cls.binary.isDefined) { val typ = cls.binary.get if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 34b7f9f8af..538a606243 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -14,7 +14,6 @@ import java.lang.Integer.toHexString import scala.collection.immutable.{Map, ListMap} import scala.collection.mutable.{ListBuffer, ArrayBuffer} import scala.tools.nsc.io.AbstractFile -import scala.tools.nsc.util.ClassRep import scala.annotation.switch /** This abstract class implements a class file parser. @@ -953,9 +952,8 @@ abstract class ClassfileParser { for (entry <- innerClasses.valuesIterator) { // create a new class member for immediate inner classes if (entry.outerName == externalName) { - val file = global.classPath.findClass(entry.externalName.toString) match { - case Some(ClassRep(Some(binary: AbstractFile), _)) => binary - case _ => throw new AssertionError(entry.externalName) + val file = global.classPath.findAbstractFile(entry.externalName.toString) getOrElse { + throw new AssertionError(entry.externalName) } enterClassAndModule(entry, new global.loaders.ClassfileLoader(file), entry.jflags) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 0c466e24f5..8a77be6d83 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -14,7 +14,6 @@ import scala.collection.mutable._ import scala.tools.nsc._ import scala.tools.nsc.backend.icode._ import scala.tools.nsc.io._ -import scala.tools.nsc.util.ClassRep import ClassfileConstants._ import Flags._ @@ -50,18 +49,10 @@ abstract class ICodeReader extends ClassfileParser { isScalaModule = cls.isModule && !cls.hasFlag(JAVA) log("Reading class: " + cls + " isScalaModule?: " + isScalaModule) val name = cls.fullName('.') + (if (sym.hasFlag(MODULE)) "$" else "") - classPath.findClass(name) match { - case Some(ClassRep(bin, _)) => - assert(bin.isDefined, "No classfile for " + cls) - classFile = bin.get.asInstanceOf[AbstractFile] -// if (isScalaModule) -// sym = cls.linkedClassOfModule - -// for (s <- cls.info.members) -// Console.println("" + s + ": " + s.tpe) - parse(classFile, sym) - case _ => - log("Could not find: " + cls) + + classPath.findAbstractFile(name) match { + case Some(classFile) => parse(classFile, sym) + case _ => log("Could not find: " + cls) } (staticCode, instanceCode) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index a5e62ff542..db559891df 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -16,9 +16,6 @@ import scala.util.Sorting import scala.collection.mutable.{ListBuffer, ArrayBuffer, HashSet => MutHashSet} import scala.tools.nsc.io.AbstractFile -import ch.epfl.lamp.compiler.msil.{Type => MSILType, Assembly} - - /** <p> * This module provides star expansion of '-classpath' option arguments, behaves the same as * java, see [http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html] @@ -61,59 +58,46 @@ object ClassPath { def expandPath(path: String, expandStar: Boolean = true): List[String] = if (expandStar) splitPath(path).flatMap(expandS(_)) else splitPath(path) - - var XO = false - - def collectTypes(assemFile: AbstractFile) = { - var res: Array[MSILType] = MSILType.EmptyTypes - val assem = Assembly.LoadFrom(assemFile.path) - if (assem != null) { - // DeclaringType == null: true for non-inner classes - res = assem.GetTypes() filter (_.DeclaringType == null) - Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0) - } - res - } -} - -/** - * Represents classes which can be loaded with a ClassfileLoader/MSILTypeLoader - * and / or a SourcefileLoader. - */ -case class ClassRep[T](binary: Option[T], source: Option[AbstractFile]) { - def name = { - if (binary.isDefined) binary.get match { - case f: AbstractFile => - assert(f.name.endsWith(".class"), f.name) - f.name dropRight 6 - case t: MSILType => - t.Name - case c => - throw new FatalError("Unexpected binary class representation: "+ c) - } else { - assert(source.isDefined) - val nme = source.get.name - if (nme.endsWith(".scala")) - nme dropRight 6 - else if (nme.endsWith(".java")) - nme dropRight 5 - else - throw new FatalError("Unexpected source file ending: " + nme) - } - } } /** * Represents a package which contains classes and other packages */ abstract class ClassPath[T] { + type AnyClassRep = ClassPath[T]#ClassRep /** * The short name of the package (without prefix) */ def name: String - val classes: List[ClassRep[T]] + val classes: List[AnyClassRep] val packages: List[ClassPath[T]] val sourcepaths: List[AbstractFile] + protected def nameOfBinaryRepresentation(binary: T): String = binary match { + case f: AbstractFile => + assert(f.name endsWith ".class", f.name) + f.name dropRight 6 + case _ => + throw new FatalError("Unexpected binary class representation: " + binary) + } + + /** + * Represents classes which can be loaded with a ClassfileLoader/MSILTypeLoader + * and / or a SourcefileLoader. + */ + case class ClassRep(binary: Option[T], source: Option[AbstractFile]) { + def name: String = binary match { + case Some(x) => nameOfBinaryRepresentation(x) + case _ => + assert(source.isDefined) + val nme = source.get.name + if (nme.endsWith(".scala")) + nme dropRight 6 + else if (nme.endsWith(".java")) + nme dropRight 5 + else + throw new FatalError("Unexpected source file ending: " + nme) + } + } /** Whether this classpath is being used for an optimized build. * Why this is necessary is something which should really be documented, @@ -136,14 +120,23 @@ abstract class ClassPath[T] { * Find a ClassRep given a class name of the form "package.subpackage.ClassName". * Does not support nested classes on .NET */ - def findClass(name: String): Option[ClassRep[T]] = { + def findClass(name: String): Option[AnyClassRep] = { val i = name.indexOf('.') if (i < 0) { - classes.find(c => c.name == name) + classes.find(_.name == name) } else { val pkg = name take i val rest = name drop (i + 1) - packages.find(p => p.name == pkg).flatMap(_.findClass(rest)) + (packages find (_.name == pkg) flatMap (_ findClass rest)) map { + case x: ClassRep => x + case x => throw new FatalError("Unexpected ClassRep '%s' found searching for name '%s'".format(x, name)) + } + } + } + def findAbstractFile(name: String): Option[AbstractFile] = { + findClass(name) match { + case Some(ClassRep(Some(x: AbstractFile), _)) => Some(x) + case _ => None } } } @@ -155,10 +148,10 @@ class SourcePath[T](dir: AbstractFile, val isOptimized: Boolean) extends ClassPa def name = dir.name lazy val classes = { - val cls = new ListBuffer[ClassRep[T]] + val cls = new ListBuffer[ClassRep] for (f <- dir.iterator) { if (!f.isDirectory && validSourceFile(f.name)) - cls += ClassRep[T](None, Some(f)) + cls += ClassRep(None, Some(f)) } cls.toList } @@ -184,7 +177,7 @@ class DirectoryClassPath(dir: AbstractFile, val isOptimized: Boolean) extends Cl def name = dir.name lazy val classes = { - val cls = new ListBuffer[ClassRep[AbstractFile]] + val cls = new ListBuffer[ClassRep] for (f <- dir.iterator) { if (!f.isDirectory && validClassFile(f.name)) cls += ClassRep(Some(f), None) @@ -206,69 +199,6 @@ class DirectoryClassPath(dir: AbstractFile, val isOptimized: Boolean) extends Cl override def toString() = "directory classpath: "+ dir.toString() } - - -/** - * A assembly file (dll / exe) containing classes and namespaces - */ -class AssemblyClassPath(types: Array[MSILType], namespace: String, val isOptimized: Boolean) extends ClassPath[MSILType] { - def name = { - val i = namespace.lastIndexOf('.') - if (i < 0) namespace - else namespace drop (i + 1) - } - - def this(assemFile: AbstractFile, isOptimized: Boolean) { - this(ClassPath.collectTypes(assemFile), "", isOptimized) - } - - private lazy val first: Int = { - var m = 0 - var n = types.length - 1 - while (m < n) { - val l = (m + n) / 2 - val res = types(l).FullName.compareTo(namespace) - if (res < 0) m = l + 1 - else n = l - } - if (types(m).FullName.startsWith(namespace)) m else types.length - } - - lazy val classes = { - val cls = new ListBuffer[ClassRep[MSILType]] - var i = first - while (i < types.length && types(i).Namespace.startsWith(namespace)) { - // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..) - if (types(i).Namespace == namespace) - cls += ClassRep(Some(types(i)), None) - i += 1 - } - cls.toList - } - - lazy val packages = { - val nsSet = new MutHashSet[String] - var i = first - while (i < types.length && types(i).Namespace.startsWith(namespace)) { - val subns = types(i).Namespace - if (subns.length > namespace.length) { - // example: namespace = "System", subns = "System.Reflection.Emit" - // => find second "." and "System.Reflection" to nsSet. - val end = subns.indexOf('.', namespace.length + 1) - nsSet += (if (end < 0) subns - else subns.substring(0, end)) - } - i += 1 - } - for (ns <- nsSet.toList) - yield new AssemblyClassPath(types, ns, isOptimized) - } - - val sourcepaths: List[AbstractFile] = Nil - - override def toString() = "assembly classpath "+ namespace -} - /** * A classpath unifying multiple class- and sourcepath entries. */ @@ -279,8 +209,8 @@ abstract class MergedClassPath[T] extends ClassPath[T] { def name = entries.head.name - lazy val classes: List[ClassRep[T]] = { - val cls = new ListBuffer[ClassRep[T]] + lazy val classes: List[AnyClassRep] = { + val cls = new ListBuffer[AnyClassRep] for (e <- entries; c <- e.classes) { val name = c.name val idx = cls.indexWhere(cl => cl.name == name) @@ -337,6 +267,7 @@ class JavaClassPath(boot: String, ext: String, user: String, source: String, Xco extends MergedClassPath[AbstractFile] { protected val entries: List[ClassPath[AbstractFile]] = assembleEntries() + private def assembleEntries(): List[ClassPath[AbstractFile]] = { import ClassPath._ val etr = new ListBuffer[ClassPath[AbstractFile]] @@ -392,59 +323,3 @@ extends MergedClassPath[AbstractFile] { etr.toList } } - -/** - * The classpath when compiling with target:msil. Binary files are represented as - * MSILType values. - */ -class MsilClassPath(ext: String, user: String, source: String, val isOptimized: Boolean) extends MergedClassPath[MSILType] { - protected val entries: List[ClassPath[MSILType]] = assembleEntries() - - private def assembleEntries(): List[ClassPath[MSILType]] = { - import ClassPath._ - val etr = new ListBuffer[ClassPath[MSILType]] - val names = new MutHashSet[String] - - // 1. Assemblies from -Xassem-extdirs - for (dirName <- expandPath(ext, expandStar = false)) { - val dir = AbstractFile.getDirectory(dirName) - if (dir ne null) { - for (file <- dir) { - val name = file.name.toLowerCase - if (name.endsWith(".dll") || name.endsWith(".exe")) { - names += name - etr += new AssemblyClassPath(file, isOptimized) - } - } - } - } - - // 2. Assemblies from -Xassem-path - for (fileName <- expandPath(user, expandStar = false)) { - val file = AbstractFile.getFile(fileName) - if (file ne null) { - val name = file.name.toLowerCase - if (name.endsWith(".dll") || name.endsWith(".exe")) { - names += name - etr += new AssemblyClassPath(file, isOptimized) - } - } - } - - def check(n: String) { - if (!names.contains(n)) - throw new AssertionError("Cannot find assembly "+ n + - ". Use -Xassem-extdirs or -Xassem-path to specify its location") - } - check("mscorlib.dll") - check("scalaruntime.dll") - - // 3. Source path - for (dirName <- expandPath(source, expandStar = false)) { - val file = AbstractFile.getDirectory(dirName) - if (file ne null) etr += new SourcePath[MSILType](file, isOptimized) - } - - etr.toList - } -} diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala new file mode 100644 index 0000000000..3f69e67233 --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala @@ -0,0 +1,154 @@ +/* NSC -- new Scala compiler + * Copyright 2006-2010 LAMP/EPFL + * @author Martin Odersky + */ + +// $Id$ + +package scala.tools.nsc +package util + +import java.io.File +import java.net.URL +import java.util.StringTokenizer +import scala.util.Sorting + +import scala.collection.mutable.{ListBuffer, ArrayBuffer, HashSet => MutHashSet} +import scala.tools.nsc.io.AbstractFile + +import ch.epfl.lamp.compiler.msil.{Type => MSILType, Assembly} + +/** Keeping the MSIL classpath code in its own file is important to make sure + * we don't accidentally introduce a dependency on msil.jar in the jvm. + */ + +object MsilClassPath { + def collectTypes(assemFile: AbstractFile) = { + var res: Array[MSILType] = MSILType.EmptyTypes + val assem = Assembly.LoadFrom(assemFile.path) + if (assem != null) { + // DeclaringType == null: true for non-inner classes + res = assem.GetTypes() filter (_.DeclaringType == null) + Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0) + } + res + } +} + +/** + * A assembly file (dll / exe) containing classes and namespaces + */ +class AssemblyClassPath(types: Array[MSILType], namespace: String, val isOptimized: Boolean) extends ClassPath[MSILType] { + def name = { + val i = namespace.lastIndexOf('.') + if (i < 0) namespace + else namespace drop (i + 1) + } + + def this(assemFile: AbstractFile, isOptimized: Boolean) { + this(MsilClassPath.collectTypes(assemFile), "", isOptimized) + } + + private lazy val first: Int = { + var m = 0 + var n = types.length - 1 + while (m < n) { + val l = (m + n) / 2 + val res = types(l).FullName.compareTo(namespace) + if (res < 0) m = l + 1 + else n = l + } + if (types(m).FullName.startsWith(namespace)) m else types.length + } + + lazy val classes = { + val cls = new ListBuffer[ClassRep] + var i = first + while (i < types.length && types(i).Namespace.startsWith(namespace)) { + // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..) + if (types(i).Namespace == namespace) + cls += ClassRep(Some(types(i)), None) + i += 1 + } + cls.toList + } + + lazy val packages = { + val nsSet = new MutHashSet[String] + var i = first + while (i < types.length && types(i).Namespace.startsWith(namespace)) { + val subns = types(i).Namespace + if (subns.length > namespace.length) { + // example: namespace = "System", subns = "System.Reflection.Emit" + // => find second "." and "System.Reflection" to nsSet. + val end = subns.indexOf('.', namespace.length + 1) + nsSet += (if (end < 0) subns + else subns.substring(0, end)) + } + i += 1 + } + for (ns <- nsSet.toList) + yield new AssemblyClassPath(types, ns, isOptimized) + } + + val sourcepaths: List[AbstractFile] = Nil + + override def toString() = "assembly classpath "+ namespace +} + +/** + * The classpath when compiling with target:msil. Binary files are represented as + * MSILType values. + */ +class MsilClassPath(ext: String, user: String, source: String, val isOptimized: Boolean) extends MergedClassPath[MSILType] { + protected val entries: List[ClassPath[MSILType]] = assembleEntries() + override protected def nameOfBinaryRepresentation(binary: MSILType) = binary.Name + + private def assembleEntries(): List[ClassPath[MSILType]] = { + import ClassPath._ + val etr = new ListBuffer[ClassPath[MSILType]] + val names = new MutHashSet[String] + + // 1. Assemblies from -Xassem-extdirs + for (dirName <- expandPath(ext, expandStar = false)) { + val dir = AbstractFile.getDirectory(dirName) + if (dir ne null) { + for (file <- dir) { + val name = file.name.toLowerCase + if (name.endsWith(".dll") || name.endsWith(".exe")) { + names += name + etr += new AssemblyClassPath(file, isOptimized) + } + } + } + } + + // 2. Assemblies from -Xassem-path + for (fileName <- expandPath(user, expandStar = false)) { + val file = AbstractFile.getFile(fileName) + if (file ne null) { + val name = file.name.toLowerCase + if (name.endsWith(".dll") || name.endsWith(".exe")) { + names += name + etr += new AssemblyClassPath(file, isOptimized) + } + } + } + + def check(n: String) { + if (!names.contains(n)) + throw new AssertionError("Cannot find assembly "+ n + + ". Use -Xassem-extdirs or -Xassem-path to specify its location") + } + check("mscorlib.dll") + check("scalaruntime.dll") + + // 3. Source path + for (dirName <- expandPath(source, expandStar = false)) { + val file = AbstractFile.getDirectory(dirName) + if (file ne null) etr += new SourcePath[MSILType](file, isOptimized) + } + + etr.toList + } +}
\ No newline at end of file diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index dcc028d489..3a4779c6b7 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -279,12 +279,11 @@ object Main { } object EmptyClasspath extends ClassPath[AbstractFile] { - import tools.nsc.util.ClassRep /** * The short name of the package (without prefix) */ def name: String = "" - val classes: List[ClassRep[AbstractFile]] = Nil + val classes: List[ClassRep] = Nil val packages: List[ClassPath[AbstractFile]] = Nil val sourcepaths: List[AbstractFile] = Nil def isOptimized = false |