From a3cde88db44b0cefd900c43733fc54df8a36a555 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Mon, 3 Jun 2019 14:00:48 -0700 Subject: [PATCH] Fix runtime scala-reflect layer For best caching performance, we want to use the scala-reflect.jar that is found in the scala instance. Also, in the runtime configuration, caching didn't work correctly because we filtered the scala reflect library from the dependency jars. We really only wanted to filter out the library jars. It also was problematic to use a LayeredClassLoader for the scala reflect layer because in a subsequent commit I add the capability for a layered classloader to load classes from its descendant loaders. This caused problems when the scala-reflect layer was a LayeredClassLoader. Instead, I add the ScalaReflectClassLoader class for better reporting. --- .../scala/sbt/internal/ClassLoaders.scala | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/main/src/main/scala/sbt/internal/ClassLoaders.scala b/main/src/main/scala/sbt/internal/ClassLoaders.scala index 773ec4813..937516a0c 100644 --- a/main/src/main/scala/sbt/internal/ClassLoaders.scala +++ b/main/src/main/scala/sbt/internal/ClassLoaders.scala @@ -76,7 +76,7 @@ private[sbt] object ClassLoaders { ) s.log.warn(s"$showJavaOptions will be ignored, $showFork is set to false") } - val exclude = dependencyJars(exportedProducts).value.toSet ++ instance.allJars + val exclude = dependencyJars(exportedProducts).value.toSet ++ instance.libraryJars val allDeps = dependencyJars(dependencyClasspath).value.filterNot(exclude) val newLoader = (classpath: Seq[File]) => { @@ -135,10 +135,22 @@ private[sbt] object ClassLoaders { val scalaLibraryLayer = layer(si.libraryJars, interfaceLoader, cache, resources, tmp) val cpFiles = fullCP.map(_._1) - val scalaReflectJar = allDependencies.find(_.getName == "scala-reflect.jar") + val scalaReflectJar = allDependencies.collectFirst { + case f if f.getName == "scala-reflect.jar" => + si.allJars.find(_.getName == "scala-reflect.jar") + }.flatten + class ScalaReflectClassLoader(jar: File) + extends URLClassLoader(Array(jar.toURI.toURL), scalaLibraryLayer) { + override def toString: String = + s"ScalaReflectClassLoader($jar, parent = $scalaLibraryLayer)" + } val scalaReflectLayer = scalaReflectJar .map { file => - layer(file :: Nil, scalaLibraryLayer, cache, resources, tmp) + cache.apply( + file -> IO.getModifiedTimeOrZero(file) :: Nil, + scalaLibraryLayer, + () => new ScalaReflectClassLoader(file) + ) } .getOrElse(scalaLibraryLayer) @@ -153,11 +165,12 @@ private[sbt] object ClassLoaders { if (layerDependencies) layer(allDependencies, resourceLayer, cache, resources, tmp) else resourceLayer + val scalaJarNames = (si.libraryJars ++ scalaReflectJar).map(_.getName).toSet // layer 4 val filteredSet = if (layerDependencies) allDependencies.toSet ++ si.libraryJars ++ scalaReflectJar else Set(si.libraryJars ++ scalaReflectJar: _*) - val dynamicClasspath = cpFiles.filterNot(filteredSet) + val dynamicClasspath = cpFiles.filterNot(f => filteredSet(f) || scalaJarNames(f.getName)) new LayeredClassLoader(dynamicClasspath, dependencyLayer, resources, tmp) } ClasspathUtilities.filterByClasspath(cpFiles, raw)