From f4dd56ca5d5adb2a9183991a7ecebc2b6a1f1fc5 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 20:59:42 +0100 Subject: synchronizes names Previously we didn't have all possible name creation facilities covered with locks, so some of them silently misbehaved and caused much grief: http://groups.google.com/group/scala-internals/browse_thread/thread/ec1d3e2c4bcb000a. This patch gets all the name factories under control. Unfortunately it comes at a performance cost, which has to be evaluated. --- src/reflect/scala/reflect/internal/Names.scala | 54 ++++++++++++---------- .../scala/reflect/runtime/SynchronizedOps.scala | 8 +++- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index c78ba72dfb..01ad18d3a0 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -21,7 +21,7 @@ trait LowPriorityNames { * @author Martin Odersky * @version 1.0, 05/02/2005 */ -trait Names extends api.Names with LowPriorityNames { +trait Names extends api.Names with LowPriorityNames { self => implicit def promoteTermNamesAsNecessary(name: Name): TermName = name.toTermName // Operations ------------------------------------------------------------- @@ -109,6 +109,26 @@ trait Names extends api.Names with LowPriorityNames { protected def newTypeName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TypeName = newTermName(cs, offset, len, cachedString).toTypeName + protected def toTypeName(termName: TermName): TypeName = { + val h = hashValue(chrs, termName.index, termName.len) & HASH_MASK + var n = typeHashtable(h) + while ((n ne null) && n.start != termName.index) + n = n.next + + if (n ne null) n + else termName.createCompanionName(h) + } + + protected def toTermName(typeName: TypeName): TermName = { + val h = hashValue(chrs, typeName.index, typeName.len) & HASH_MASK + var n = termHashtable(h) + while ((n ne null) && n.start != typeName.index) + n = n.next + + if (n ne null) n + else typeName.createCompanionName(h) + } + /** Create a term name from string. */ def newTermName(s: String): TermName = newTermName(s.toCharArray(), 0, s.length(), null) @@ -145,7 +165,7 @@ trait Names extends api.Names with LowPriorityNames { * or Strings as Names. Give names the key functions the absence of which * make people want Strings all the time. */ - sealed abstract class Name(protected val index: Int, protected val len: Int) extends NameApi { + sealed abstract class Name(protected[Names] val index: Int, protected[Names] val len: Int) extends NameApi { type ThisNameType >: Null <: Name protected[this] def thisName: ThisNameType @@ -463,21 +483,21 @@ trait Names extends api.Names with LowPriorityNames { * TermName_R and TypeName_R recreate it each time toString is called. */ private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { - protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) + @inline final def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) override def newName(str: String): TermName = newTermNameCached(str) } private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { - protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) + @inline final def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) override def newName(str: String): TypeName = newTypeNameCached(str) } private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { - protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) + @inline final def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) override def toString = new String(chrs, index, len) } private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { - protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) + @inline final def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) override def toString = new String(chrs, index, len) } @@ -490,22 +510,14 @@ trait Names extends api.Names with LowPriorityNames { def isTermName: Boolean = true def isTypeName: Boolean = false def toTermName: TermName = this - def toTypeName: TypeName = { - val h = hashValue(chrs, index, len) & HASH_MASK - var n = typeHashtable(h) - while ((n ne null) && n.start != index) - n = n.next - - if (n ne null) n - else createCompanionName(h) - } + def toTypeName: TypeName = self.toTypeName(this) def newName(str: String): TermName = newTermName(str) def companionName: TypeName = toTypeName def subName(from: Int, to: Int): TermName = newTermName(chrs, start + from, to - from) def nameKind = "term" - protected def createCompanionName(h: Int): TypeName + def createCompanionName(h: Int): TypeName } implicit val TermNameTag = ClassTag[TermName](classOf[TermName]) @@ -518,15 +530,7 @@ trait Names extends api.Names with LowPriorityNames { typeHashtable(hash) = this def isTermName: Boolean = false def isTypeName: Boolean = true - def toTermName: TermName = { - val h = hashValue(chrs, index, len) & HASH_MASK - var n = termHashtable(h) - while ((n ne null) && n.start != index) - n = n.next - - if (n ne null) n - else createCompanionName(h) - } + def toTermName: TermName = self.toTermName(this) def toTypeName: TypeName = this def newName(str: String): TypeName = newTypeName(str) def companionName: TermName = toTermName diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala index d022bf66ba..f9f4a26b42 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala @@ -13,8 +13,12 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable // therefore we don't have a danger of a deadlock from having a fine-grained lock for name creation private lazy val nameLock = new Object - override def newTermName(s: String): TermName = nameLock.synchronized { super.newTermName(s) } - override def newTypeName(s: String): TypeName = nameLock.synchronized { super.newTypeName(s) } + // these three methods are the only gateways into name hashtable manipulations + // we need to protected them with a lock, because they are by far not atomic + override protected def newTermName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TermName = + nameLock.synchronized { super.newTermName(cs, offset, len, cachedString) } + override protected def toTypeName(termName: TermName): TypeName = nameLock.synchronized { super.toTypeName(termName) } + override protected def toTermName(typeName: TypeName): TermName = nameLock.synchronized { super.toTermName(typeName) } // BaseTypeSeqs -- cgit v1.2.3