diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2016-04-24 17:23:20 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2016-12-02 11:30:47 +1000 |
commit | 159480f2504cc08f9cc35660cc33090a49e0228e (patch) | |
tree | 741982f0327fd013d6f218b5582adea5d7d93fd4 /src/compiler | |
parent | bfa7ade0db6d36efc721e36dc41627dbd76b0176 (diff) | |
download | scala-159480f2504cc08f9cc35660cc33090a49e0228e.tar.gz scala-159480f2504cc08f9cc35660cc33090a49e0228e.tar.bz2 scala-159480f2504cc08f9cc35660cc33090a49e0228e.zip |
Support Java 9 modular runtime images
http://openjdk.java.net/jeps/220 changes the layout of the
JDK to encapsulate the provided libraries with the new module
system.
This commit modifies the compiler's classpath implementation
to scan the new location of these, the `jrt://` virtual filesystem.
This might need to be adjusted once we provide a means for
users to specify the subset of modules that they want to
depend on, but for now reclaims the ground we lost.
```
⚡ (java_use 9-ea; qscala)
Welcome to Scala 2.12.0-20160908-223617-7e4ebda (Java HotSpot(TM) 64-Bit Server VM, Java 9-ea).
Type in expressions for evaluation. Or try :help.
scala> import StackWalker._, java.util.stream._, scala.collection.JavaConverters._
import StackWalker._
import java.util.stream._
import scala.collection.JavaConverters._
scala> (() => StackWalker.getInstance(java.util.EnumSet.of(Option.RETAIN_CLASS_REFERENCE)).walk[Seq[String]]((s: java.util.stream.Stream[StackFrame]) => s.iterator.asScala.take(3).map(_.toString).toList)).apply().mkString("\n")
res0: String =
.$anonfun$res0$1(<console>:21)
.<init>(<console>:21)
.<clinit>(<console>)
scala>
```
I've marked the new class, `NioFile` as `private[scala]` to justify
the forward compatibility whitelist entry.
In principle we could use NioFile more widely rather than `PlainFile`
I tried this out in https://github.com/retronym/scala/commit/b2d0a17a
which passed CI. But to be conservative, I'm not submitting that change
at this point.
Diffstat (limited to 'src/compiler')
4 files changed, 57 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala index 3a29f1ba11..80c5ec8828 100644 --- a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala +++ b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala @@ -4,6 +4,7 @@ package scala.tools.nsc.classpath import scala.reflect.io.{AbstractFile, VirtualDirectory} +import scala.reflect.io.Path.string2path import scala.tools.nsc.Settings import FileUtils.AbstractFileOps import scala.tools.nsc.util.ClassPath @@ -52,7 +53,10 @@ class ClassPathFactory(settings: Settings) { protected def classesInPathImpl(path: String, expand: Boolean) = for { file <- expandPath(path, expand) - dir <- Option(AbstractFile.getDirectory(file)) + dir <- { + def asImage = if (file.endsWith(".jimage")) Some(AbstractFile.getFile(file)) else None + Option(AbstractFile.getDirectory(file)).orElse(asImage) + } } yield newClassPath(dir) private def createSourcePath(file: AbstractFile): ClassPath = diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala index c4be59d7eb..133a656206 100644 --- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala @@ -4,7 +4,9 @@ package scala.tools.nsc.classpath import java.io.File -import java.net.URL +import java.net.{URI, URL} +import java.nio.file.{FileSystems, Files, SimpleFileVisitor} +import java.util.function.IntFunction import java.util import java.util.Comparator @@ -119,6 +121,53 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo def asClassPathStrings: Seq[String] = Seq(dir.getPath) } +object JImageDirectoryLookup { + import java.nio.file._, java.net.URI, scala.collection.JavaConverters._ + def apply(): List[ClassPath] = { + try { + val fs = FileSystems.getFileSystem(URI.create("jrt:/")) + val dir: Path = fs.getPath("/modules") + val modules = Files.list(dir).iterator().asScala.toList + modules.map(m => new JImageDirectoryLookup(fs, m.getFileName.toString)) + } catch { + case _: ProviderNotFoundException | _: FileSystemNotFoundException => + Nil + } + } +} +class JImageDirectoryLookup(fs: java.nio.file.FileSystem, module: String) extends DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { + import java.nio.file.Path, java.nio.file._ + type F = Path + val dir: Path = fs.getPath("/modules/" + module) + + protected def emptyFiles: Array[Path] = Array.empty + protected def getSubDir(packageDirName: String): Option[Path] = { + val packageDir = dir.resolve(packageDirName) + if (Files.exists(packageDir) && Files.isDirectory(packageDir)) Some(packageDir) + else None + } + protected def listChildren(dir: Path, filter: Option[Path => Boolean]): Array[Path] = { + import scala.collection.JavaConverters._ + val f = filter.getOrElse((p: Path) => true) + Files.list(dir).iterator().asScala.filter(f).toArray[Path] + } + protected def getName(f: Path): String = f.getFileName.toString + protected def toAbstractFile(f: Path): AbstractFile = new scala.reflect.io.PlainNioFile(f) + protected def isPackage(f: Path): Boolean = Files.isDirectory(f) && mayBeValidPackage(f.getFileName.toString) + + def asURLs: Seq[URL] = Seq(dir.toUri.toURL) + def asClassPathStrings: Seq[String] = asURLs.map(_.toString) + + def findClassFile(className: String): Option[AbstractFile] = { + val relativePath = FileUtils.dirPath(className) + ".class" + val classFile = dir.resolve(relativePath) + if (Files.exists(classFile)) Some(new scala.reflect.io.PlainNioFile(classFile)) else None + } + override protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file) + override protected def isMatchingFile(f: Path): Boolean = Files.isRegularFile(f) && f.getFileName.toString.endsWith(".class") + override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage) +} + case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl diff --git a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala index bbcfcb24ca..2ade83c6f9 100644 --- a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala +++ b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala @@ -63,7 +63,7 @@ object FileUtils { // probably it should match a pattern like [a-z_]{1}[a-z0-9_]* but it cannot be changed // because then some tests in partest don't pass - private def mayBeValidPackage(dirName: String): Boolean = + def mayBeValidPackage(dirName: String): Boolean = (dirName != "META-INF") && (dirName != "") && (dirName.charAt(0) != '.') def mkFileFilter(f: JFile => Boolean) = new FileFilter { diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index c351b6ace1..188cabbc8d 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -234,6 +234,7 @@ final class PathResolver(settings: Settings) { // Assemble the elements! def basis = List[Traversable[ClassPath]]( + JImageDirectoryLookup.apply(), // 0. The Java 9 classpath (backed by the jrt:/ virtual system) classesInPath(javaBootClassPath), // 1. The Java bootstrap class path. contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path. classesInExpandedPath(javaUserClassPath), // 3. The Java application class path. |