Skip to content

Commit 837f924

Browse files
committed
Rework closure of macro classloaders
1 parent bec5899 commit 837f924

File tree

5 files changed

+22
-20
lines changed

5 files changed

+22
-20
lines changed

src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,8 @@ trait MacroRuntimes extends JavaReflectionRuntimes {
5454
/** Macro classloader that is used to resolve and run macro implementations.
5555
* Loads classes from from -cp (aka the library classpath).
5656
* Is also capable of detecting REPL and reusing its classloader.
57-
*
58-
* When -Xmacro-jit is enabled, we sometimes fallback to on-the-fly compilation of macro implementations,
59-
* which compiles implementations into a virtual directory (very much like REPL does) and then conjures
60-
* a classloader mapped to that virtual directory.
6157
*/
62-
private lazy val defaultMacroClassloaderCache = {
63-
def attemptClose(loader: ClassLoader): Unit = {
64-
if (!scala.tools.nsc.typechecker.Macros.macroClassLoadersCache.owns(loader)) {
65-
loader match {
66-
case u: URLClassLoader => debuglog("Closing macro runtime classloader"); u.close()
67-
case afcl: AbstractFileClassLoader => attemptClose(afcl.getParent)
68-
case _ => ???
69-
}
70-
}
71-
}
72-
perRunCaches.newGeneric(findMacroClassLoader, attemptClose _)
73-
}
58+
private lazy val defaultMacroClassloaderCache: () => ClassLoader = perRunCaches.newGeneric(findMacroClassLoader())
7459
def defaultMacroClassloader: ClassLoader = defaultMacroClassloaderCache()
7560

7661
/** Abstracts away resolution of macro runtimes.

src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ final class FileBasedCache[T] {
190190
import java.nio.file.Path
191191
private case class Stamp(lastModified: FileTime, fileKey: Object)
192192
private val cache = collection.mutable.Map.empty[Seq[Path], (Seq[Stamp], T)]
193-
def owns(t: T): Boolean = cache.valuesIterator.exists(_._2.asInstanceOf[AnyRef] eq t.asInstanceOf[AnyRef])
194193

195194
def getOrCreate(paths: Seq[Path], create: () => T): T = cache.synchronized {
196195
val stamps = paths.map { path =>

src/compiler/scala/tools/nsc/plugins/Plugins.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@ trait Plugins { global: Global =>
164164
// TODO if the only null is jrt:// we can still cache
165165
// TODO filter out classpath elements pointing to non-existing files before we get here, that's another source of null
166166
analyzer.macroLogVerbose(s"macro classloader: caching is disabled because `AbstractFile.getURL` returned `null` for ${hasNullURL.map(_._1).mkString(", ")}.")
167-
newLoader()
167+
perRunCaches.recordClassloader(newLoader())
168168
} else {
169169
val locations = urlsAndFiles.map(t => Path(t._2.file))
170170
val nonJarZips = locations.filterNot(Jar.isJarOrZip(_))
171171
if (nonJarZips.nonEmpty) {
172172
analyzer.macroLogVerbose(s"macro classloader: caching is disabled because the following paths are not supported: ${nonJarZips.mkString(",")}.")
173-
newLoader()
173+
perRunCaches.recordClassloader(newLoader())
174174
} else {
175175
Macros.macroClassLoadersCache.getOrCreate(locations.map(_.jfile.toPath()), newLoader)
176176
}

src/compiler/scala/tools/reflect/ReflectGlobal.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ReflectGlobal(currentSettings: Settings, reporter: Reporter, override val
3232
*/
3333
override protected[scala] def findMacroClassLoader(): ClassLoader = {
3434
val classpath = classPath.asURLs
35-
ScalaClassLoader.fromURLs(classpath, rootClassLoader)
35+
perRunCaches.recordClassloader(ScalaClassLoader.fromURLs(classpath, rootClassLoader))
3636
}
3737

3838
override def transformedType(sym: Symbol) =

src/reflect/scala/reflect/internal/SymbolTable.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ package scala
1414
package reflect
1515
package internal
1616

17+
import java.net.URLClassLoader
18+
1719
import scala.annotation.elidable
1820
import scala.collection.mutable
1921
import util._
@@ -415,6 +417,22 @@ abstract class SymbolTable extends macros.Universe
415417
cache
416418
}
417419

420+
/** Closes the provided classloader at the conclusion of this Run */
421+
final def recordClassloader(loader: ClassLoader): ClassLoader = {
422+
def attemptClose(loader: ClassLoader): Unit = {
423+
loader match {
424+
case u: URLClassLoader => debuglog("Closing classloader " + u); u.close()
425+
case _ =>
426+
}
427+
}
428+
caches ::= new WeakReference((new Clearable {
429+
def clear(): Unit = {
430+
attemptClose(loader)
431+
}
432+
}))
433+
loader
434+
}
435+
418436
/**
419437
* Removes a cache from the per-run caches. This is useful for testing: it allows running the
420438
* compiler and then inspect the state of a cache.

0 commit comments

Comments
 (0)