diff --git a/compiler/src/dotty/tools/MainGenericCompiler.scala b/compiler/src/dotty/tools/MainGenericCompiler.scala index 36342becb8a4..98b1b31f06a5 100644 --- a/compiler/src/dotty/tools/MainGenericCompiler.scala +++ b/compiler/src/dotty/tools/MainGenericCompiler.scala @@ -7,10 +7,8 @@ import java.io.File import java.lang.Thread import scala.annotation.internal.sharable import dotty.tools.dotc.util.ClasspathFromClassloader -import dotty.tools.runner.ObjectRunner import dotty.tools.dotc.config.Properties.envOrNone import dotty.tools.io.Jar -import dotty.tools.runner.ScalaClassLoader import java.nio.file.Paths import dotty.tools.dotc.config.CommandLineParser import dotty.tools.scripting.StringDriver diff --git a/compiler/src/dotty/tools/backend/WorklistAlgorithm.scala b/compiler/src/dotty/tools/backend/WorklistAlgorithm.scala deleted file mode 100644 index b3d98d425b2a..000000000000 --- a/compiler/src/dotty/tools/backend/WorklistAlgorithm.scala +++ /dev/null @@ -1,57 +0,0 @@ -package dotty.tools -package backend - -/** - * Simple implementation of a worklist algorithm. A processing - * function is applied repeatedly to the first element in the - * worklist, as long as the stack is not empty. - * - * The client class should mix-in this class and initialize the worklist - * field and define the `processElement` method. Then call the `run` method - * providing a function that initializes the worklist. - * - * @author Martin Odersky - * @version 1.0 - * @see [[scala.tools.nsc.backend.icode.Linearizers]] - */ -trait WorklistAlgorithm { - type Elem - class WList { - private var list: List[Elem] = Nil - def isEmpty = list.isEmpty - def nonEmpty = !isEmpty - def push(e: Elem): Unit = { list = e :: list } - def pop(): Elem = { - val head = list.head - list = list.tail - head - } - def pushAll(xs: Iterable[Elem]): Unit = xs.foreach(push) - def clear(): Unit = list = Nil - - } - - val worklist: WList - - /** - * Run the iterative algorithm until the worklist remains empty. - * The initializer is run once before the loop starts and should - * initialize the worklist. - */ - def run(initWorklist: => Unit) = { - initWorklist - - while (worklist.nonEmpty) - processElement(dequeue) - } - - /** - * Process the current element from the worklist. - */ - def processElement(e: Elem): Unit - - /** - * Remove and return the first element to be processed from the worklist. - */ - def dequeue: Elem -} diff --git a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala index 622e074b9047..2a9ada9c092a 100644 --- a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala @@ -8,7 +8,7 @@ import java.net.{URI, URL} import java.nio.file.{FileSystems, Files} import dotty.tools.dotc.classpath.PackageNameUtils.{packageContains, separatePkgAndClassNames} -import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation, EfficientClassPath, JDK9Reflectors} +import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation, EfficientClassPath} import FileUtils.* import PlainFile.toPlainFile @@ -124,34 +124,21 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo } object JrtClassPath { - import java.nio.file.*, java.net.URI - def apply(release: Option[String]): Option[ClassPath] = { - import scala.util.Properties.* - if (!isJavaAtLeast("9")) None - else { - // Longer term we'd like an official API for this in the JDK - // Discussion: http://mail.openjdk.java.net/pipermail/compiler-dev/2018-March/thread.html#11738 - - val currentMajorVersion: Int = JDK9Reflectors.runtimeVersionMajor(JDK9Reflectors.runtimeVersion()).intValue() - release match { - case Some(v) if v.toInt < currentMajorVersion => - try { - val ctSym = Paths.get(javaHome).resolve("lib").resolve("ct.sym") - if (Files.notExists(ctSym)) None - else Some(new CtSymClassPath(ctSym, v.toInt)) - } catch { - case NonFatal(_) => None - } - case _ => - try { - val fs = FileSystems.getFileSystem(URI.create("jrt:/")) - Some(new JrtClassPath(fs)) - } catch { - case _: ProviderNotFoundException | _: FileSystemNotFoundException => None - } - } - } - } + import java.nio.file.*, java.net.URI, scala.util.Properties + def apply(release: Option[String]): Option[ClassPath] = + // Longer term we'd like an official API for this in the JDK + // Discussion: http://mail.openjdk.java.net/pipermail/compiler-dev/2018-March/thread.html#11738 + release match + case Some(v) if v.toInt < Runtime.version().feature() => + try + val ctSym = Paths.get(Properties.javaHome).resolve("lib").resolve("ct.sym") + if (Files.notExists(ctSym)) None + else Some(new CtSymClassPath(ctSym, v.toInt)) + catch case NonFatal(_) => None + case _ => + try Some(new JrtClassPath(FileSystems.getFileSystem(URI.create("jrt:/")))) + catch case _: ProviderNotFoundException | _: FileSystemNotFoundException => None + end apply } /** @@ -228,11 +215,9 @@ final class CtSymClassPath(ctSym: java.nio.file.Path, release: Int) extends Clas // e.g. "java.lang" -> Seq(/876/java/lang, /87/java/lang, /8/java/lang)) private val packageIndex: scala.collection.Map[String, scala.collection.Seq[Path]] = { val index = collection.mutable.HashMap[String, collection.mutable.ListBuffer[Path]]() - val isJava12OrHigher = scala.util.Properties.isJavaAtLeast("12") rootsForRelease.foreach(root => Files.walk(root).iterator().asScala.filter(Files.isDirectory(_)).foreach { p => - val moduleNamePathElementCount = if (isJava12OrHigher) 1 else 0 - if (p.getNameCount > root.getNameCount + moduleNamePathElementCount) { - val packageDotted = p.subpath(moduleNamePathElementCount + root.getNameCount, p.getNameCount).toString.replace('/', '.') + if (p.getNameCount > root.getNameCount + 1) { + val packageDotted = p.subpath(1 + root.getNameCount, p.getNameCount).toString.replace('/', '.') index.getOrElseUpdate(packageDotted, new collection.mutable.ListBuffer) += p } }) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 21cdc31a94df..5de274184244 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -6,7 +6,7 @@ import dotty.tools.dotc.config.Settings.{Setting, SettingAlias, SettingGroup, Se import dotty.tools.dotc.config.SourceVersion import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.rewrites.Rewrites -import dotty.tools.io.{AbstractFile, Directory, JDK9Reflectors, PlainDirectory, NoAbstractFile} +import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, NoAbstractFile} import Setting.ChoiceWithHelp import ScalaSettingCategories.* diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala index b7d953c6abed..60c71d8ceda6 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala @@ -3,7 +3,7 @@ package config import Settings.Setting.ChoiceWithHelp import dotty.tools.backend.jvm.BackendUtils.classfileVersionMap -import dotty.tools.io.{AbstractFile, Directory, JDK9Reflectors, PlainDirectory, NoAbstractFile} +import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, NoAbstractFile} object ScalaSettingsProperties: @@ -16,7 +16,7 @@ object ScalaSettingsProperties: (minTargetVersion to maxTargetVersion).toList.map(_.toString) def supportedReleaseVersions: List[String] = - val jdkVersion = JDK9Reflectors.runtimeVersionMajor(JDK9Reflectors.runtimeVersion()).intValue() + val jdkVersion = Runtime.version().feature() val maxVersion = Math.min(jdkVersion, maxTargetVersion) (minReleaseVersion to maxVersion).toList.map(_.toString) diff --git a/compiler/src/dotty/tools/io/JDK9Reflectors.java b/compiler/src/dotty/tools/io/JDK9Reflectors.java deleted file mode 100644 index 9816cc03f92a..000000000000 --- a/compiler/src/dotty/tools/io/JDK9Reflectors.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package dotty.tools.io; - -import java.io.IOException; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.jar.JarFile; - -public final class JDK9Reflectors { - private static final MethodHandle RUNTIME_VERSION_PARSE; - private static final MethodHandle RUNTIME_VERSION; - private static final MethodHandle RUNTIME_VERSION_MAJOR; - private static final MethodHandle NEW_JAR_FILE; - - static { - RUNTIME_VERSION_PARSE = lookupRuntimeVersionParse(); - RUNTIME_VERSION = lookupRuntimeVersion(); - RUNTIME_VERSION_MAJOR = lookupRuntimeVersionMajor(); - NEW_JAR_FILE = lookupNewJarFile(); - } - - // Classes from java.lang.Runtime are not available in JDK 8 so using them explicitly would prevent this file from compiling with JDK 8 - // but these methods are not called in runtime when using this version of JDK - - public static /*java.lang.Runtime.Version*/ Object runtimeVersionParse(String string) { - try { - return RUNTIME_VERSION_PARSE == null ? null : RUNTIME_VERSION_PARSE.invoke(string); - } catch (Throwable t) { - return null; - } - } - - public static /*java.lang.Runtime.Version*/ Object runtimeVersion() { - try { - return RUNTIME_VERSION == null ? null : RUNTIME_VERSION.invoke(); - } catch (Throwable t) { - return null; - } - } - - public static /*java.lang.Runtime.Version*/ Integer runtimeVersionMajor(/*java.lang.Runtime.Version*/ Object version) { - try { - return RUNTIME_VERSION_MAJOR == null ? null : (Integer) (int) RUNTIME_VERSION_MAJOR.invoke(version); - } catch (Throwable t) { - return null; - } - } - - public static JarFile newJarFile(java.io.File file, boolean verify, int mode, /*java.lang.Runtime.Version*/ Object version) throws IOException { - try { - if (version == null) return new JarFile(file, verify, mode); - else { - return NEW_JAR_FILE == null ? null : (JarFile) NEW_JAR_FILE.invoke(file, verify, mode, version); - } - } catch (IOException | IllegalArgumentException | SecurityException ex) { - throw ex; - } catch (Throwable t) { - throw new RuntimeException(t); - } - - } - - private static MethodHandle lookupRuntimeVersionParse() { - try { - return MethodHandles.lookup().findStatic(runtimeVersionClass(), "parse", MethodType.methodType(runtimeVersionClass(), String.class)); - } catch (Throwable t) { - return null; - } - } - private static MethodHandle lookupRuntimeVersion() { - try { - return MethodHandles.lookup().findStatic(java.lang.Runtime.class, "version", MethodType.methodType(runtimeVersionClass())); - } catch (Throwable t) { - return null; - } - } - private static MethodHandle lookupRuntimeVersionMajor() { - try { - return MethodHandles.lookup().findVirtual(runtimeVersionClass(), "major", MethodType.methodType(Integer.TYPE)); - } catch (Throwable t) { - return null; - } - } - private static MethodHandle lookupNewJarFile() { - try { - return MethodHandles.lookup().findConstructor(java.util.jar.JarFile.class, MethodType.methodType(void.class, java.io.File.class, java.lang.Boolean.TYPE, Integer.TYPE, runtimeVersionClass())); - } catch (Throwable t) { - return null; - } - } - private static Class runtimeVersionClass() throws ClassNotFoundException { - return Class.forName("java.lang.Runtime$Version"); - } -} diff --git a/compiler/src/dotty/tools/io/ZipArchive.scala b/compiler/src/dotty/tools/io/ZipArchive.scala index 1ee79bd8036a..5e6aa10f6638 100644 --- a/compiler/src/dotty/tools/io/ZipArchive.scala +++ b/compiler/src/dotty/tools/io/ZipArchive.scala @@ -11,7 +11,7 @@ import java.net.URL import java.io.{ IOException, InputStream, OutputStream, FilterInputStream } import java.nio.file.Files import java.util.zip.{ ZipEntry, ZipFile } -import java.util.jar.Manifest +import java.util.jar.{ Manifest, JarFile } import scala.collection.mutable import scala.jdk.CollectionConverters.* @@ -117,8 +117,7 @@ final class FileZipArchive(jpath: JPath, release: Option[String]) extends ZipArc private def openZipFile(): ZipFile = try { release match { case Some(r) if file.getName.endsWith(".jar") => - val releaseVersion = JDK9Reflectors.runtimeVersionParse(r) - JDK9Reflectors.newJarFile(file, true, ZipFile.OPEN_READ, releaseVersion) + new JarFile(file, true, ZipFile.OPEN_READ, Runtime.Version.parse(r)) case _ => new ZipFile(file) } diff --git a/compiler/src/dotty/tools/runner/ObjectRunner.scala b/compiler/src/dotty/tools/runner/ObjectRunner.scala deleted file mode 100644 index 62dbcc32f30d..000000000000 --- a/compiler/src/dotty/tools/runner/ObjectRunner.scala +++ /dev/null @@ -1,48 +0,0 @@ -package dotty.tools -package runner - -import java.net.URL -import scala.util.control.NonFatal -import java.lang.reflect.InvocationTargetException -import java.lang.reflect.UndeclaredThrowableException -import java.util.concurrent.ExecutionException - -/** - * This is a copy implementation from scala/scala scala.tools.nsc.CommonRunner trait - */ -trait CommonRunner { - /** Run a given object, specified by name, using a - * specified classpath and argument list. - * - * @throws java.lang.ClassNotFoundException - * @throws java.lang.NoSuchMethodException - * @throws java.lang.reflect.InvocationTargetException - */ - def run(urls: Seq[URL], objectName: String, arguments: Seq[String]): Unit = { - import RichClassLoader.* - ScalaClassLoader.fromURLsParallelCapable(urls).run(objectName, arguments) - } - - /** Catches any non-fatal exception thrown by run (in the case of InvocationTargetException, - * unwrapping it) and returns it in an Option. - */ - def runAndCatch(urls: Seq[URL], objectName: String, arguments: Seq[String]): Option[Throwable] = - try { run(urls, objectName, arguments) ; None } - catch { case NonFatal(e) => Some(rootCause(e)) } - - private def rootCause(x: Throwable): Throwable = x match { - case _: InvocationTargetException | - _: ExceptionInInitializerError | - _: UndeclaredThrowableException | - _: ExecutionException - if x.getCause != null => - rootCause(x.getCause.nn) - case _ => x - } -} - -/** An object that runs another object specified by name. - * - * @author Lex Spoon - */ -object ObjectRunner extends CommonRunner diff --git a/compiler/src/dotty/tools/runner/ScalaClassLoader.scala b/compiler/src/dotty/tools/runner/ScalaClassLoader.scala deleted file mode 100644 index 0cb31189be5f..000000000000 --- a/compiler/src/dotty/tools/runner/ScalaClassLoader.scala +++ /dev/null @@ -1,81 +0,0 @@ -package dotty.tools -package runner - - -import java.lang.ClassLoader -import java.lang.invoke.{MethodHandles, MethodType} -import java.lang.reflect.Modifier -import java.net.{ URL, URLClassLoader } -import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException } - -import scala.annotation.internal.sharable -import scala.annotation.tailrec -import scala.util.control.Exception.catching - -final class RichClassLoader(private val self: ClassLoader) extends AnyVal { - /** Execute an action with this classloader as context classloader. */ - private def asContext[T](action: => T): T = ScalaClassLoader.asContext(self)(action) - - /** Load and link a class with this classloader */ - def tryToLoadClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, initialize = false) - - /** Load, link and initialize a class with this classloader */ - def tryToInitializeClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, initialize = true) - - private def tryClass[T <: AnyRef](path: String, initialize: Boolean): Option[Class[T]] = - catching(classOf[ClassNotFoundException], classOf[SecurityException]) opt - Class.forName(path, initialize, self).asInstanceOf[Class[T]] - - /** Run the main method of a class to be loaded by this classloader */ - def run(objectName: String, arguments: Seq[String]): Unit = { - val clsToRun = tryToInitializeClass(objectName).getOrElse(throw new ClassNotFoundException(objectName)) - val method = clsToRun.getMethod("main", classOf[Array[String]]) - if !Modifier.isStatic(method.getModifiers) then - throw new NoSuchMethodException(s"$objectName.main is not static") - try asContext(method.invoke(null, Array(arguments.toArray: AnyRef)*)) - catch unwrapHandler({ case ex => throw ex }) - } - - @tailrec private def unwrapThrowable(x: Throwable): Throwable = x match { - case _: InvocationTargetException | // thrown by reflectively invoked method or constructor - _: ExceptionInInitializerError | // thrown when running a static initializer (e.g. a scala module constructor) - _: UndeclaredThrowableException | // invocation on a proxy instance if its invocation handler's `invoke` throws an exception - _: ClassNotFoundException | // no definition for a class instantiated by name - _: NoClassDefFoundError // the definition existed when the executing class was compiled, but can no longer be found - if x.getCause != null => - unwrapThrowable(x.getCause) - case _ => x - } - - // Transforms an exception handler into one which will only receive the unwrapped - // exceptions (for the values of wrap covered in unwrapThrowable.) - private def unwrapHandler[T](pf: PartialFunction[Throwable, T]): PartialFunction[Throwable, T] = - pf.compose({ case ex => unwrapThrowable(ex) }) -} - -object RichClassLoader { - implicit def wrapClassLoader(loader: ClassLoader): RichClassLoader = new RichClassLoader(loader) -} - -object ScalaClassLoader { - def setContext(cl: ClassLoader) = Thread.currentThread.setContextClassLoader(cl) - - def fromURLsParallelCapable(urls: Seq[URL], parent: ClassLoader | Null = null): URLClassLoader = - new URLClassLoader(urls.toArray, if parent == null then bootClassLoader else parent) - - @sharable private val bootClassLoader: ClassLoader | Null = - if scala.util.Properties.isJavaAtLeast("9") then - try - ClassLoader.getSystemClassLoader.getParent - catch case _: Throwable => null - else null - - extension (classLoader: ClassLoader) - /** Execute an action with this classloader as context classloader. */ - def asContext[T](action: => T): T = - val saved = Thread.currentThread.getContextClassLoader - try - setContext(classLoader) - action - finally setContext(saved) -} diff --git a/repl/src/dotty/tools/repl/DependencyResolver.scala b/repl/src/dotty/tools/repl/DependencyResolver.scala index 732b69e1721b..a830ce6007f3 100644 --- a/repl/src/dotty/tools/repl/DependencyResolver.scala +++ b/repl/src/dotty/tools/repl/DependencyResolver.scala @@ -91,7 +91,7 @@ object DependencyResolver: import dotty.tools.dotc.core.SymbolLoaders import dotty.tools.dotc.core.Symbols.defn import dotty.tools.io.* - import dotty.tools.runner.ScalaClassLoader.fromURLsParallelCapable + import dotty.tools.repl.ScalaClassLoader.fromURLsParallelCapable // Create a classloader with all the resolved JAR files val urls = files.map(_.toURI.toURL).toArray diff --git a/repl/src/dotty/tools/repl/ReplDriver.scala b/repl/src/dotty/tools/repl/ReplDriver.scala index 298c44487f2e..00a12bd1b8bc 100644 --- a/repl/src/dotty/tools/repl/ReplDriver.scala +++ b/repl/src/dotty/tools/repl/ReplDriver.scala @@ -34,7 +34,7 @@ import dotc.util.{SourceFile, SourcePosition} import dotc.{CompilationUnit, Driver} import dotc.config.CompilerCommand import dotty.tools.io.{AbstractFileClassLoader => _, *} -import dotty.tools.runner.ScalaClassLoader.* +import dotty.tools.repl.ScalaClassLoader.* import org.jline.reader.* diff --git a/repl/src/dotty/tools/repl/ScalaClassLoader.scala b/repl/src/dotty/tools/repl/ScalaClassLoader.scala new file mode 100644 index 000000000000..417d5a19cdfe --- /dev/null +++ b/repl/src/dotty/tools/repl/ScalaClassLoader.scala @@ -0,0 +1,34 @@ +package dotty.tools.repl + +import java.lang.ClassLoader +import java.lang.invoke.{MethodHandles, MethodType} +import java.lang.reflect.Modifier +import java.net.{ URL, URLClassLoader } +import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException } + +import scala.annotation.internal.sharable +import scala.annotation.tailrec +import scala.util.control.Exception.catching + +object ScalaClassLoader { + def setContext(cl: ClassLoader) = Thread.currentThread.setContextClassLoader(cl) + + def fromURLsParallelCapable(urls: Seq[URL], parent: ClassLoader | Null = null): URLClassLoader = + new URLClassLoader(urls.toArray, if parent == null then bootClassLoader else parent) + + @sharable private val bootClassLoader: ClassLoader | Null = + if scala.util.Properties.isJavaAtLeast("9") then + try + ClassLoader.getSystemClassLoader.getParent + catch case _: Throwable => null + else null + + extension (classLoader: ClassLoader) + /** Execute an action with this classloader as context classloader. */ + def asContext[T](action: => T): T = + val saved = Thread.currentThread.getContextClassLoader + try + setContext(classLoader) + action + finally setContext(saved) +}