From 974735b01f3c08d9fef02b8ab5f086d2d689a590 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 8 May 2009 22:02:14 +0000 Subject: Explicit locking on Symbol creation so multiple... Explicit locking on Symbol creation so multiple readers don't have to block up on synchronize. Closes bug #1307. --- src/library/scala/Symbol.scala | 84 ++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/library/scala/Symbol.scala b/src/library/scala/Symbol.scala index becb37bc96..610cc839c3 100644 --- a/src/library/scala/Symbol.scala +++ b/src/library/scala/Symbol.scala @@ -11,13 +11,6 @@ package scala -// jcl disabled for now; go directly to java collections. -//import scala.collection.jcl - -//private[scala] object internedSymbols extends jcl.WeakHashMap[String, ref.WeakReference[Symbol]] -private[scala] object internedSymbols - extends java.util.WeakHashMap[String, java.lang.ref.WeakReference[Symbol]] - /**

* This class provides a simple way to get unique objects for * equal strings. Since symbols are interned, they can be compared using @@ -37,7 +30,6 @@ private[scala] object internedSymbols */ @serializable final class Symbol private (val name: String) { - /** Converts this symbol to a string. */ override def toString(): String = "'" + name @@ -46,34 +38,56 @@ final class Symbol private (val name: String) { private def readResolve(): Any = Symbol.apply(name) } -object Symbol { +object Symbol extends UniquenessCache[String, Symbol] +{ + protected def valueFromKey(name: String): Symbol = new Symbol(name) + protected def keyFromValue(sym: Symbol): Option[String] = Some(sym.name) +} - /**

- * Makes this symbol into a unique reference. - *

- *

- * If two interened symbols are equal (i.e. they have the same name) - * then they must be identical (wrt reference equality). - *

- * - * @return the unique reference to this string. - */ - def apply(name: String): Symbol = internedSymbols.synchronized { -// internedSymbols.get(name).flatMap(_.get) match { -// case Some(sym) => sym -// case _ => -// val sym = new Symbol(name) -// internedSymbols(name) = new ref.WeakReference(sym) -// sym - var sym: Symbol = null - val ref = internedSymbols.get(name) - if (ref != null) sym = ref.get - if (sym == null) { - sym = new Symbol(name) - internedSymbols.put(name, new java.lang.ref.WeakReference(sym)) +/** This is private so it won't appear in the library API, but + * abstracted to offer some hope of reusability. */ +private[scala] abstract class UniquenessCache[K, V >: Null] +{ + import java.lang.ref.{ ReferenceQueue, WeakReference } + import java.util.WeakHashMap + import java.util.concurrent.locks.ReentrantReadWriteLock + + private val queue = new ReferenceQueue[V] + private val rwl = new ReentrantReadWriteLock() + private val rlock = rwl.readLock + private val wlock = rwl.writeLock + private val map = new WeakHashMap[K, WeakReference[V]] + + protected def valueFromKey(k: K): V + protected def keyFromValue(v: V): Option[K] + + def apply(name: K): V = { + def cached(): V = { + rlock.lock + try { + val reference = map get name + if (reference == null) null + else reference.get // will be null if we were gc-ed + } + finally rlock.unlock + } + def updateCache(): V = { + wlock.lock + try { + val res = cached() + if (res != null) res + else { + val sym = valueFromKey(name) + map.put(name, new WeakReference(sym, queue)) + sym + } + } + finally wlock.unlock } - sym - } - def unapply(other: Symbol): Option[String] = Some(other.name) + val res = cached() + if (res == null) updateCache() + else res + } + def unapply(other: V): Option[K] = keyFromValue(other) } -- cgit v1.2.3