Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
xeno-by committed Feb 7, 2013
1 parent 365321b commit a57495c
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 27 deletions.
54 changes: 29 additions & 25 deletions src/reflect/scala/reflect/internal/Names.scala
Expand Up @@ -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 -------------------------------------------------------------
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
}

Expand All @@ -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])
Expand All @@ -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
Expand Down
8 changes: 6 additions & 2 deletions src/reflect/scala/reflect/runtime/SynchronizedOps.scala
Expand Up @@ -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

Expand Down

2 comments on commit a57495c

@scala-jenkins
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Job pr-rangepos-per-commit failed for a57495c (results):


Took 3 min.
sad kitty
to rebuild, comment "PLS REBUILD/pr-rangepos-per-commit@a57495c87df05faececfb6129400cfbf509e2a17"on PR #2083

@scala-jenkins
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Job pr-checkin-per-commit failed for a57495c (results):


Took 3 min.
sad kitty
to rebuild, comment "PLS REBUILD/pr-checkin-per-commit@a57495c87df05faececfb6129400cfbf509e2a17"on PR #2083

Please sign in to comment.