summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-09-24 20:09:03 -0700
committerPaul Phillips <paulp@improving.org>2012-09-24 20:09:03 -0700
commitdb8dea0055739ec39c8765565c5f479ab360acf9 (patch)
treea4d70326a55b7062536a34e1ec89b7216ec21138 /src/reflect
parentffaa3cb89edc1407c99c89f36248358c16887fe7 (diff)
parent759de8623923d17eaca373dcec14899681a52df4 (diff)
downloadscala-db8dea0055739ec39c8765565c5f479ab360acf9.tar.gz
scala-db8dea0055739ec39c8765565c5f479ab360acf9.tar.bz2
scala-db8dea0055739ec39c8765565c5f479ab360acf9.zip
Merge pull request #1385 from scalamacros/ticket/6412
SI-6412 some fixes for reflection leaks
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Importers.scala164
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala12
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala13
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala24
4 files changed, 121 insertions, 92 deletions
diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala
index c116928d37..02209d0712 100644
--- a/src/reflect/scala/reflect/internal/Importers.scala
+++ b/src/reflect/scala/reflect/internal/Importers.scala
@@ -1,6 +1,8 @@
package scala.reflect
package internal
+
import scala.collection.mutable.WeakHashMap
+import scala.ref.WeakReference
// SI-6241: move importers to a mirror
trait Importers extends api.Importers { self: SymbolTable =>
@@ -26,8 +28,20 @@ trait Importers extends api.Importers { self: SymbolTable =>
val from: SymbolTable
- lazy val symMap: WeakHashMap[from.Symbol, Symbol] = new WeakHashMap
- lazy val tpeMap: WeakHashMap[from.Type, Type] = new WeakHashMap
+ protected lazy val symMap = new Cache[from.Symbol, Symbol]()
+ protected lazy val tpeMap = new Cache[from.Type, Type]()
+ protected class Cache[K <: AnyRef, V <: AnyRef] extends WeakHashMap[K, WeakReference[V]] {
+ def weakGet(key: K): Option[V] = this get key flatMap WeakReference.unapply
+ def weakUpdate(key: K, value: V) = this.update(key, WeakReference(value))
+ def weakGetOrElseUpdate(key: K)(value: => V): V =
+ weakGet(key) match {
+ case Some(result) => result
+ case None =>
+ val result = value
+ this(key) = WeakReference(result)
+ result
+ }
+ }
// fixups and maps prevent stackoverflows in importer
var pendingSyms = 0
@@ -44,8 +58,10 @@ trait Importers extends api.Importers { self: SymbolTable =>
object reverse extends from.StandardImporter {
val from: self.type = self
- for ((fromsym, mysym) <- StandardImporter.this.symMap) symMap += ((mysym, fromsym))
- for ((fromtpe, mytpe) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, fromtpe))
+ // FIXME this and reverse should be constantly kept in sync
+ // not just synced once upon the first usage of reverse
+ for ((fromsym, WeakReference(mysym)) <- StandardImporter.this.symMap) symMap += ((mysym, WeakReference(fromsym)))
+ for ((fromtpe, WeakReference(mytpe)) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, WeakReference(fromtpe)))
}
// todo. careful import of positions
@@ -53,70 +69,70 @@ trait Importers extends api.Importers { self: SymbolTable =>
pos.asInstanceOf[Position]
def importSymbol(sym0: from.Symbol): Symbol = {
- def doImport(sym: from.Symbol): Symbol = {
- if (symMap.contains(sym))
- return symMap(sym)
-
- val myowner = importSymbol(sym.owner)
- val mypos = importPosition(sym.pos)
- val myname = importName(sym.name).toTermName
- val myflags = sym.flags
- def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = {
- symMap(x) = mysym
- mysym.referenced = op(x.referenced)
- mysym
- }
- val mysym = sym match {
- case x: from.MethodSymbol =>
- linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol)
- case x: from.ModuleSymbol =>
- linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, importSymbol)
- case x: from.FreeTermSymbol =>
- newFreeTermSymbol(importName(x.name).toTermName, x.value, x.flags, x.origin) setInfo importType(x.info)
- case x: from.FreeTypeSymbol =>
- newFreeTypeSymbol(importName(x.name).toTypeName, x.flags, x.origin)
- case x: from.TermSymbol =>
- linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol)
- case x: from.TypeSkolem =>
- val origin = x.unpackLocation match {
- case null => null
- case y: from.Tree => importTree(y)
- case y: from.Symbol => importSymbol(y)
+ def doImport(sym: from.Symbol): Symbol =
+ symMap weakGet sym match {
+ case Some(result) => result
+ case _ =>
+ val myowner = importSymbol(sym.owner)
+ val mypos = importPosition(sym.pos)
+ val myname = importName(sym.name).toTermName
+ val myflags = sym.flags
+ def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = {
+ symMap.weakUpdate(x, mysym)
+ mysym.referenced = op(x.referenced)
+ mysym
}
- myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags)
- case x: from.ModuleClassSymbol =>
- val mysym = myowner.newModuleClass(myname.toTypeName, mypos, myflags)
- symMap(x) = mysym
- mysym.sourceModule = importSymbol(x.sourceModule)
- mysym
- case x: from.ClassSymbol =>
- val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags)
- symMap(x) = mysym
- if (sym.thisSym != sym) {
- mysym.typeOfThis = importType(sym.typeOfThis)
- mysym.thisSym setName importName(sym.thisSym.name)
+ val mysym = sym match {
+ case x: from.MethodSymbol =>
+ linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol)
+ case x: from.ModuleSymbol =>
+ linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, importSymbol)
+ case x: from.FreeTermSymbol =>
+ newFreeTermSymbol(importName(x.name).toTermName, x.value, x.flags, x.origin) setInfo importType(x.info)
+ case x: from.FreeTypeSymbol =>
+ newFreeTypeSymbol(importName(x.name).toTypeName, x.flags, x.origin)
+ case x: from.TermSymbol =>
+ linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol)
+ case x: from.TypeSkolem =>
+ val origin = x.unpackLocation match {
+ case null => null
+ case y: from.Tree => importTree(y)
+ case y: from.Symbol => importSymbol(y)
+ }
+ myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags)
+ case x: from.ModuleClassSymbol =>
+ val mysym = myowner.newModuleClass(myname.toTypeName, mypos, myflags)
+ symMap.weakUpdate(x, mysym)
+ mysym.sourceModule = importSymbol(x.sourceModule)
+ mysym
+ case x: from.ClassSymbol =>
+ val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags)
+ symMap.weakUpdate(x, mysym)
+ if (sym.thisSym != sym) {
+ mysym.typeOfThis = importType(sym.typeOfThis)
+ mysym.thisSym setName importName(sym.thisSym.name)
+ }
+ mysym
+ case x: from.TypeSymbol =>
+ myowner.newTypeSymbol(myname.toTypeName, mypos, myflags)
}
- mysym
- case x: from.TypeSymbol =>
- myowner.newTypeSymbol(myname.toTypeName, mypos, myflags)
- }
- symMap(sym) = mysym
- mysym setFlag Flags.LOCKED
- mysym setInfo {
- val mytypeParams = sym.typeParams map importSymbol
- new LazyPolyType(mytypeParams) {
- override def complete(s: Symbol) {
- val result = sym.info match {
- case from.PolyType(_, res) => res
- case result => result
+ symMap.weakUpdate(sym, mysym)
+ mysym setFlag Flags.LOCKED
+ mysym setInfo {
+ val mytypeParams = sym.typeParams map importSymbol
+ new LazyPolyType(mytypeParams) {
+ override def complete(s: Symbol) {
+ val result = sym.info match {
+ case from.PolyType(_, res) => res
+ case result => result
+ }
+ s setInfo GenPolyType(mytypeParams, importType(result))
+ s setAnnotations (sym.annotations map importAnnotationInfo)
+ }
}
- s setInfo GenPolyType(mytypeParams, importType(result))
- s setAnnotations (sym.annotations map importAnnotationInfo)
}
- }
- }
- mysym resetFlag Flags.LOCKED
- } // end doImport
+ mysym resetFlag Flags.LOCKED
+ } // end doImport
def importOrRelink: Symbol = {
val sym = sym0 // makes sym visible in the debugger
@@ -186,14 +202,10 @@ trait Importers extends api.Importers { self: SymbolTable =>
} // end importOrRelink
val sym = sym0
- if (symMap contains sym) {
- symMap(sym)
- } else {
+ symMap.weakGetOrElseUpdate(sym) {
pendingSyms += 1
-
- try {
- symMap getOrElseUpdate (sym, importOrRelink)
- } finally {
+ try importOrRelink
+ finally {
pendingSyms -= 1
tryFixup()
}
@@ -258,14 +270,10 @@ trait Importers extends api.Importers { self: SymbolTable =>
def importOrRelink: Type =
doImport(tpe)
- if (tpeMap contains tpe) {
- tpeMap(tpe)
- } else {
+ tpeMap.weakGetOrElseUpdate(tpe) {
pendingTpes += 1
-
- try {
- tpeMap getOrElseUpdate (tpe, importOrRelink)
- } finally {
+ try importOrRelink
+ finally {
pendingTpes -= 1
tryFixup()
}
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index bde7f7ac51..4836db5db0 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -10,10 +10,15 @@ package internal
import Flags._
trait Mirrors extends api.Mirrors {
- self: SymbolTable =>
+ thisUniverse: SymbolTable =>
override type Mirror >: Null <: RootsBase
+ // root symbols hold a strong reference to the enclosing mirror
+ // this prevents the mirror from being collected
+ // if there are any symbols created by that mirror
+ trait RootSymbol extends Symbol { def mirror: Mirror }
+
abstract class RootsBase(rootOwner: Symbol) extends MirrorOf[Mirrors.this.type] { thisMirror =>
protected[scala] def rootLoader: LazyType
@@ -70,7 +75,7 @@ trait Mirrors extends api.Mirrors {
protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol
- protected def universeMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name)
+ protected def universeMissingHook(owner: Symbol, name: Name): Symbol = thisUniverse.missingHook(owner, name)
private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name)
@@ -251,10 +256,11 @@ trait Mirrors extends api.Mirrors {
}
// Features common to RootClass and RootPackage, the roots of all
// type and term symbols respectively.
- sealed trait RootSymbol extends WellKnownSymbol {
+ sealed trait RootSymbol extends WellKnownSymbol with thisUniverse.RootSymbol {
final override def isRootSymbol = true
override def owner = rootOwner
override def typeOfThis = thisSym.tpe
+ def mirror = thisMirror.asInstanceOf[Mirror]
}
// This is the package _root_. The actual root cannot be referenced at
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 0d9e90d3a6..2f12ba59a2 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -1236,16 +1236,9 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUnive
override def scopeTransform(owner: Symbol)(op: => Scope): Scope =
if (owner.isPackageClass) owner.info.decls else op
- private lazy val rootToLoader = new WeakHashMap[Symbol, ClassLoader]
-
- override def mirrorThatLoaded(sym: Symbol): Mirror = {
- val root = sym.enclosingRootClass
- def findLoader = {
- val loaders = (mirrors collect { case (cl, ref) if ref.get.get.RootClass == root => cl })
- assert(loaders.nonEmpty, sym)
- loaders.head
- }
- mirrors(rootToLoader getOrElseUpdate(root, findLoader)).get.get
+ override def mirrorThatLoaded(sym: Symbol): Mirror = sym.enclosingRootClass match {
+ case root: RootSymbol => root.mirror
+ case _ => abort(s"${sym}.enclosingRootClass = ${sym.enclosingRootClass}, which is not a RootSymbol")
}
private lazy val syntheticCoreClasses: Map[(String, Name), Symbol] = {
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index de029ca658..b9b140a2fd 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -1,6 +1,9 @@
package scala.reflect
package runtime
+import scala.collection.mutable.WeakHashMap
+import java.lang.ref.WeakReference
+
/** This trait overrides methods in reflect.internal, bracketing
* them in synchronized { ... } to make them thread-safe
*/
@@ -11,7 +14,26 @@ trait SynchronizedTypes extends internal.Types { self: SymbolTable =>
private object uniqueLock
- override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { super.unique(tp) }
+ private val uniques = WeakHashMap[Type, WeakReference[Type]]()
+ override def unique[T <: Type](tp: T): T = uniqueLock.synchronized {
+ // we need to have weak uniques for runtime reflection
+ // because unlike the normal compiler universe, reflective universe isn't organized in runs
+ // therefore perRunCaches can grow infinitely large
+ //
+ // despite that toolbox universes are decorated, toolboxes are compilers,
+ // i.e. they have their caches cleaned up automatically on per-run basis,
+ // therefore they should use vanilla uniques, which are faster
+ if (!isCompilerUniverse) {
+ val result = if (uniques contains tp) uniques(tp).get else null
+ if (result ne null) result.asInstanceOf[T]
+ else {
+ uniques(tp) = new WeakReference(tp)
+ tp
+ }
+ } else {
+ super.unique(tp)
+ }
+ }
class SynchronizedUndoLog extends UndoLog {
private val actualLock = new java.util.concurrent.locks.ReentrantLock