diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 0a3c3d24ce5a..c0d0f5b0de51 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -41,6 +41,8 @@ import scala.tools.nsc.classpath._ import scala.tools.nsc.profile.Profiler import scala.util.control.NonFatal import java.io.Closeable +import java.util.concurrent.atomic.AtomicReference + import scala.annotation.tailrec class Global(var currentSettings: Settings, reporter0: LegacyReporter) @@ -1731,6 +1733,17 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter) perRunCaches.clearAll() closeableRegistry.close() } + override protected def newNameTable: NameTable = { + if (currentSettings.YcacheNameTable) { + var shared: NameTable = null + do { + shared = Global.nameTableCache.get + if (shared == null) Global.nameTableCache.compareAndSet(null, new scala.reflect.internal.NameTable) + } while (shared == null) + shared + } + else super.newNameTable + } } object Global { @@ -1743,4 +1756,5 @@ object Global { override def keepsTypeParams = false def run(): Unit = { throw new Error("InitPhase.run") } } + private val nameTableCache = new AtomicReference[scala.reflect.internal.NameTable] } diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 8b8b589021ac..b3292a75c593 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -251,6 +251,7 @@ trait ScalaSettings extends AbsScalaSettings val YcachePluginClassLoader = CachePolicy.setting("plugin", "compiler plugins") val YcacheMacroClassLoader = CachePolicy.setting("macro", "macros") val YmacroClasspath = PathSetting ("-Ymacro-classpath", "The classpath used to reflectively load macro implementations, default is the compilation classpath.", "") + val YcacheNameTable = BooleanSetting ("-Ycache-name-table", "Share a single name table for concurrently running instances of the compiler") val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method") diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index c17acf25ebae..ecfb60a65906 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -55,30 +55,82 @@ trait Names { // @deprecated("use explicit `TypeName(s)` instead", "2.11.0") // implicit def stringToTypeName(s: String): TypeName = TypeName(s) + type NameTable <: NameTableApi + + val nameTable: NameTable + /** The abstract type of names. * @group Names */ - type Name >: Null <: AnyRef with NameApi + type Name >: Null <: AnyRef with nameTable.NameApi /** The abstract type of names representing terms. * @group Names */ - type TypeName >: Null <: TypeNameApi with Name + type TypeName >: Null <: nameTable.TypeNameApi with Name + /** The abstract type of names representing types. + * @group Names + */ + type TermName >: Null <: nameTable.TermNameApi with Name + + /** The API of Name instances. + * @group API + */ + type NameApi <: nameTable.NameApi + + /** Create a new term name. + * @group Names + */ + @deprecated("use TermName instead", "2.11.0") + def newTermName(s: String): TermName + + /** Creates a new type name. + * @group Names + */ + @deprecated("use TypeName instead", "2.11.0") + def newTypeName(s: String): TypeName + + /** The constructor/extractor for `TermName` instances. + * @group Extractors + */ + val TermName: TermNameExtractor + + /** An extractor class to create and pattern match with syntax `TermName(s)`. + * @group Extractors + */ + abstract class TermNameExtractor { + def apply(s: String): TermName + def unapply(name: TermName): Option[String] + } + + /** The constructor/extractor for `TypeName` instances. + * @group Extractors + */ + val TypeName: TypeNameExtractor + + /** An extractor class to create and pattern match with syntax `TypeName(s)`. + * @group Extractors + */ + abstract class TypeNameExtractor { + def apply(s: String): TypeName + def unapply(name: TypeName): Option[String] + } +} + +abstract class NameTableApi { + /** The abstract type of names. + * @group Names + */ + type Name >: Null <: AnyRef with NameApi + + type TypeName >: Null <: TypeNameApi with Name - /** Has no special methods. Is here to provides erased identity for `TypeName`. - * @group API - */ - trait TypeNameApi /** The abstract type of names representing types. * @group Names */ type TermName >: Null <: TermNameApi with Name - /** Has no special methods. Is here to provides erased identity for `TermName`. - * @group API - */ - trait TermNameApi /** The API of Name instances. * @group API @@ -116,6 +168,15 @@ trait Names { */ def encodedName: Name } + /** Has no special methods. Is here to provides erased identity for `TypeName`. + * @group API + */ + trait TypeNameApi extends NameApi + /** Has no special methods. Is here to provides erased identity for `TermName`. + * @group API + */ + trait TermNameApi extends NameApi + /** Create a new term name. * @group Names @@ -129,29 +190,4 @@ trait Names { @deprecated("use TypeName instead", "2.11.0") def newTypeName(s: String): TypeName - /** The constructor/extractor for `TermName` instances. - * @group Extractors - */ - val TermName: TermNameExtractor - - /** An extractor class to create and pattern match with syntax `TermName(s)`. - * @group Extractors - */ - abstract class TermNameExtractor { - def apply(s: String): TermName - def unapply(name: TermName): Option[String] - } - - /** The constructor/extractor for `TypeName` instances. - * @group Extractors - */ - val TypeName: TypeNameExtractor - - /** An extractor class to create and pattern match with syntax `TypeName(s)`. - * @group Extractors - */ - abstract class TypeNameExtractor { - def apply(s: String): TypeName - def unapply(name: TypeName): Option[String] - } } diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 24c9f2322501..42a847e50c37 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -16,30 +16,51 @@ package internal import java.util.concurrent.ConcurrentHashMap +import scala.reflect.api.NameTableApi + trait Names extends api.Names { - def nameTableSize: Int = cache.size + type NameTable = scala.reflect.internal.NameTable + override val nameTable: NameTable = newNameTable - override final type Name = AName - override final type TypeName = TermNameImpl#TypeNameImpl - override final type TermName = TermNameImpl + protected def newNameTable: NameTable = new NameTable + + def nameTableSize: Int = nameTable.nameTableSize + override final type Name = nameTable.AName + override final type TypeName = nameTable.TypeNameImpl + override final type TermName = nameTable.TermNameImpl implicit final val NameTag = ClassTag[Name](classOf[Name]) implicit final val TermNameTag = ClassTag[TermName](classOf[TermName]) implicit final val TypeNameTag = ClassTag[TypeName](classOf[TypeName]) - - override object TermName extends TermNameExtractor { - @inline override def apply(s: String): TermName = newTermName(s) - override def unapply(name: TermName): Option[String] = Some(name.rawString) + override final def newTypeName(value: String): TypeName = nameTable.newTypeName(value) + override final def newTermName(value: String): TermName = nameTable.newTermName(value) + object TermName extends TermNameExtractor { + def apply(s: String) = newTermName(s) + def unapply(name: TermName): Option[String] = Some(name.toString) } - override object TypeName extends TypeNameExtractor { - @inline override def apply(s: String): TypeName = newTypeName(s) - override def unapply(name: TypeName): Option[String] = Some(name.rawString) + object TypeName extends TypeNameExtractor { + def apply(s: String) = newTypeName(s) + def unapply(name: TypeName): Option[String] = Some(name.toString) } - override final def newTypeName(value: String): TypeName = newTermName(value).companionName + //deprecated stuff + @deprecated + @inline final def newTermNameCached(s: String): TermName = newTermName(s) + + @deprecated + @inline final def newTypeNameCached(s: String): TypeName = newTypeName(s) +} +class NameTable extends NameTableApi { + override final type Name = AName + override final type TypeName = TypeNameImpl + override final type TermName = TermNameImpl + + def nameTableSize: Int = cache.size + + private[this] final val cache = new ConcurrentHashMap[String, TermNameImpl](1000, 0.75F, 1) - override final def newTermName(value: String): TermName = { - //TODO consider a better structure to use than a CHM + override final def newTermName(value: String): TermNameImpl = { + //TODO consider a better structure to use than a CHM var res = cache.get(value) if (res eq null) { val next = new TermNameImpl(value) @@ -50,10 +71,7 @@ trait Names extends api.Names { res //same as cache.computeIfAbsent(value, new NameHolder(_)) but faster } - private[this] final val cache = new ConcurrentHashMap[String, TermName](1000, 0.75F, 1) - //deprecated stuff - @deprecated @inline final def newTermNameCached(s: String): TermName = newTermName(s) - @deprecated @inline final def newTypeNameCached(s: String): TypeName = newTypeName(s) + final def newTypeName(value:String): TypeName = newTermName(value).companionName abstract sealed class AName extends NameApi with CharSequence { type ThisNameType <: AName @@ -61,14 +79,14 @@ trait Names extends api.Names { override final def subSequence(start: Int, end: Int): CharSequence = value.subSequence(start, end) override def decoded: String = decodedName.toString override def encoded: String = encodedName.toString - @inline private[Names] def rawString = value - override def decodedName: ThisNameType - override def encodedName: ThisNameType + @inline private[NameTable] def rawString = value + def decodedName: ThisNameType + def encodedName: ThisNameType //non API methods protected def value: String - def companionName: Name + def companionName: AName /** Return the subname with characters from from to to-1. */ def subName(from: Int, to: Int): ThisNameType = @@ -250,12 +268,12 @@ trait Names extends api.Names { } final class TermNameImpl(override val toString: String) extends AName with TermNameApi { type ThisNameType = TermName + override def isTermName = true override def isTypeName = false override protected def value: String = toString - override def toTermName: TermName = this override def toTypeName: TypeName = typeName @@ -269,7 +287,7 @@ trait Names extends api.Names { def identifier = identifier_ & 0x80FF def markAsIdentifier(java: Boolean, newIdentifier: Int) { require((identifier.toShort & 0x80FF) == identifier.toShort) - val flag = (if (java) 0x1000 else 0x2000).toShort + val flag = (if (java) 0x1000 else 0x2000).toShort if (identifier_ == 0) { //first call this.identifier_ = (newIdentifier | flag).toShort @@ -290,31 +308,30 @@ trait Names extends api.Names { else this } override lazy final val encodedName: TermName = { - val res = NameTransformer.encode(value) - if (res == value) this else newName(res) - } - - private lazy val typeName:TypeName = new TypeNameImpl + val res = NameTransformer.encode(value) + if (res == value) this else newName(res) + } + private[NameTable] lazy val typeName: TypeNameImpl = new TypeNameImpl(this) - final class TypeNameImpl extends AName with TypeNameApi { - type ThisNameType = TypeName - override def isTermName = false - override def isTypeName = true - override def decodedName: TypeName = TermNameImpl.this.decodedName.typeName - override def encodedName: TypeName = TermNameImpl.this.encodedName.typeName + } + final class TypeNameImpl(term: TermNameImpl) extends AName with TypeNameApi { + type ThisNameType = TypeName + override def isTermName = false + override def isTypeName = true + override def decodedName: TypeName = term.decodedName.typeName + override def encodedName: TypeName = term.encodedName.typeName - override protected def value: String = TermNameImpl.this.toString - override def toString: String = TermNameImpl.this.toString + override protected def value: String = term.toString + override def toString: String = term.toString - override def toTermName: TermName = TermNameImpl.this - override def toTypeName: TypeName = this + override def toTermName: TermName = term + override def toTypeName: TypeName = this - override def companionName = TermNameImpl.this - override def newName(str: String) = newTypeName(str) - override def nameKind = "type" - def debugString = decoded + "!" - } + override def companionName = term + override def newName(str: String) = newTypeName(str) + override def nameKind = "type" + def debugString = decoded + "!" } } diff --git a/test/files/run/reflection-names.check b/test/files/run/reflection-names.check index f8cb78cc67b4..09e69a1a23fe 100644 --- a/test/files/run/reflection-names.check +++ b/test/files/run/reflection-names.check @@ -1,4 +1,4 @@ (java.lang.String,bc) -(scala.reflect.internal.Names$TermName_R,bc) -(scala.reflect.internal.Names$TypeName_R,bc) -(scala.reflect.internal.Names$TypeName_R,bc) +(scala.reflect.internal.NameTable$TermNameImpl,bc) +(scala.reflect.internal.NameTable$TypeNameImpl,bc) +(scala.reflect.internal.NameTable$TypeNameImpl,bc)