package scala package reflect package runtime import scala.collection.mutable import java.lang.ref.{WeakReference => jWeakRef} import scala.ref.{WeakReference => sWeakRef} import scala.reflect.internal.Depth /** This trait overrides methods in reflect.internal, bracketing * them in synchronized { ... } to make them thread-safe */ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTable => // No sharing of map objects: override protected def commonOwnerMap = new CommonOwnerMap // we can keep this lock fine-grained, because super.unique just updates the cache // and, in particular, doesn't call any reflection APIs which makes deadlocks impossible private lazy val uniqueLock = new Object private val uniques = mutable.WeakHashMap[Type, jWeakRef[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 inCache = uniques get tp val result = if (inCache.isDefined) inCache.get.get else null if (result ne null) result.asInstanceOf[T] else { uniques(tp) = new jWeakRef(tp) tp } } else { super.unique(tp) } } private lazy val _skolemizationLevel = mkThreadLocalStorage(0) override def skolemizationLevel = _skolemizationLevel.get override def skolemizationLevel_=(value: Int) = _skolemizationLevel.set(value) private lazy val _undoLog = mkThreadLocalStorage(new UndoLog) override def undoLog = _undoLog.get private lazy val _intersectionWitness = mkThreadLocalStorage(perRunCaches.newWeakMap[List[Type], sWeakRef[Type]]()) override def intersectionWitness = _intersectionWitness.get private lazy val _subsametypeRecursions = mkThreadLocalStorage(0) override def subsametypeRecursions = _subsametypeRecursions.get override def subsametypeRecursions_=(value: Int) = _subsametypeRecursions.set(value) private lazy val _pendingSubTypes = mkThreadLocalStorage(new mutable.HashSet[SubTypePair]) override def pendingSubTypes = _pendingSubTypes.get private lazy val _basetypeRecursions = mkThreadLocalStorage(0) override def basetypeRecursions = _basetypeRecursions.get override def basetypeRecursions_=(value: Int) = _basetypeRecursions.set(value) private lazy val _pendingBaseTypes = mkThreadLocalStorage(new mutable.HashSet[Type]) override def pendingBaseTypes = _pendingBaseTypes.get private lazy val _lubResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type]) override def lubResults = _lubResults.get private lazy val _glbResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type]) override def glbResults = _glbResults.get private lazy val _indent = mkThreadLocalStorage("") override def indent = _indent.get override def indent_=(value: String) = _indent.set(value) private lazy val _toStringRecursions = mkThreadLocalStorage(0) override def toStringRecursions = _toStringRecursions.get override def toStringRecursions_=(value: Int) = _toStringRecursions.set(value) private lazy val _toStringSubjects = mkThreadLocalStorage(new mutable.HashSet[Type]) override def toStringSubjects = _toStringSubjects.get /* The idea of caches is as follows. * When in reflexive mode, a cache is either null, or one sentinel * value representing undefined or the final defined * value. Hence, we can ask in non-synchronized mode whether the cache field * is non null and different from the sentinel (if a sentinel exists). * If that's true, the cache value is current. * Otherwise we arrive in one of the defined... methods listed below * which go through all steps in synchronized mode. */ override protected def defineUnderlyingOfSingleType(tpe: SingleType) = gilSynchronized { super.defineUnderlyingOfSingleType(tpe) } override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = gilSynchronized { super.defineBaseTypeSeqOfCompoundType(tpe) } override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = gilSynchronized { super.defineBaseClassesOfCompoundType(tpe) } override protected def defineParentsOfTypeRef(tpe: TypeRef) = gilSynchronized { super.defineParentsOfTypeRef(tpe) } override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = gilSynchronized { super.defineBaseTypeSeqOfTypeRef(tpe) } }