diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-07-24 15:28:12 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-07-24 16:08:25 +0200 |
commit | 2eff6601dac2b19c3898e46999b0ab1523ff0c0c (patch) | |
tree | d15c136615ac920411331acc1a1ce9cfc54147b3 /src | |
parent | f5f7570778586e8230439c4dbacb5f49dea185ff (diff) | |
download | scala-2eff6601dac2b19c3898e46999b0ab1523ff0c0c.tar.gz scala-2eff6601dac2b19c3898e46999b0ab1523ff0c0c.tar.bz2 scala-2eff6601dac2b19c3898e46999b0ab1523ff0c0c.zip |
SI-6058 makes JavaMirror caches weak
As discussed on reflection meeting on 2012/07/19, runtime reflection caches
need to be weak. This way we prevent leaks in long-running reflection-based
applications (the primary target here being SBT).
Diffstat (limited to 'src')
-rw-r--r-- | src/reflect/scala/reflect/runtime/TwoWayCache.scala | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/src/reflect/scala/reflect/runtime/TwoWayCache.scala b/src/reflect/scala/reflect/runtime/TwoWayCache.scala index c7bfb3435d..f47d59e411 100644 --- a/src/reflect/scala/reflect/runtime/TwoWayCache.scala +++ b/src/reflect/scala/reflect/runtime/TwoWayCache.scala @@ -1,27 +1,40 @@ package scala.reflect package runtime +import collection.mutable.WeakHashMap +import java.lang.ref.WeakReference + /** A cache that maintains a bijection between Java reflection type `J` * and Scala reflection type `S`. + * + * The cache is two-way weak (i.e. is powered by weak references), + * so that neither Java artifacts prevent Scala artifacts from being garbage collected, + * nor the other way around. */ -import collection.mutable.HashMap - private[runtime] class TwoWayCache[J, S] { - private val toScalaMap = new HashMap[J, S] - private val toJavaMap = new HashMap[S, J] + private val toScalaMap = new WeakHashMap[J, WeakReference[S]] + private val toJavaMap = new WeakHashMap[S, WeakReference[J]] def enter(j: J, s: S) = synchronized { // debugInfo("cached: "+j+"/"+s) - toScalaMap(j) = s - toJavaMap(s) = j + toScalaMap(j) = new WeakReference(s) + toJavaMap(s) = new WeakReference(j) + } + + private object SomeRef { + def unapply[T](optRef: Option[WeakReference[T]]): Option[T] = + if (optRef.nonEmpty) { + val result = optRef.get.get + if (result != null) Some(result) else None + } else None } def toScala(key: J)(body: => S): S = synchronized { toScalaMap get key match { - case Some(v) => + case SomeRef(v) => v - case none => + case None => val result = body enter(key, result) result @@ -30,9 +43,9 @@ private[runtime] class TwoWayCache[J, S] { def toJava(key: S)(body: => J): J = synchronized { toJavaMap get key match { - case Some(v) => + case SomeRef(v) => v - case none => + case None => val result = body enter(result, key) result @@ -41,11 +54,12 @@ private[runtime] class TwoWayCache[J, S] { def toJavaOption(key: S)(body: => Option[J]): Option[J] = synchronized { toJavaMap get key match { + case SomeRef(v) => + Some(v) case None => val result = body for (value <- result) enter(value, key) result - case some => some } } } |